Compare commits
97 Commits
node-group
...
temp-abc-f
Author | SHA1 | Date | |
---|---|---|---|
c0ef2a5cf5 | |||
5a0efc9c8b | |||
1ca7821b15 | |||
7ce3751757 | |||
70a80c7faa | |||
789d82ffc9 | |||
1ce6836849 | |||
b392982e3c | |||
7d7232c142 | |||
5b64e59b76 | |||
f43ccc010d | |||
21c395fa83 | |||
6143f97531 | |||
491fc93fc6 | |||
711794ffab | |||
e48f74fe4d | |||
749748c140 | |||
bf103be1eb | |||
d05fd030df | |||
ce7abd00ec | |||
b5088f19ff | |||
ed062656fa | |||
04af3002d2 | |||
4617835753 | |||
50a306e799 | |||
3f278af8e7 | |||
c1178d6d6e | |||
08e90abdee | |||
7c1ddc7755 | |||
4a5756bc35 | |||
82610dcb7c | |||
793e0f85c7 | |||
b5d861904a | |||
c54e260c34 | |||
74138fb2d4 | |||
2529300f69 | |||
4a5082317e | |||
f3594f83e1 | |||
90dcbcb236 | |||
26672cb7b5 | |||
899a790bf4 | |||
ade48c51ba | |||
0183d70df2 | |||
0c71d949c0 | |||
945b118a15 | |||
b709e64dbd | |||
d2e6fcfb77 | |||
3c6df4305d | |||
ede08b7b48 | |||
ad698d8001 | |||
872da801a8 | |||
1b2b41110f | |||
d5aea45a86 | |||
1b0b987db2 | |||
487e4b09f6 | |||
5794312f89 | |||
1cee4aa18c | |||
a89d5e9fcc | |||
33e42a1755 | |||
18877cedb2 | |||
a90012ceeb | |||
f62d9b3b8f | |||
a83dfe5c3f | |||
4bea7c806a | |||
d081856bc5 | |||
6e16db01df | |||
baab3e3a4f | |||
0ec0a097bd | |||
9c45860cc4 | |||
f5efb15b30 | |||
290f0d4d89 | |||
a3723635e8 | |||
2fa51473df | |||
5243afbcd8 | |||
9a19253ab2 | |||
16bc4e2607 | |||
a3f7f4bdfe | |||
9369691900 | |||
01b5ff266a | |||
e2a0c5dfbf | |||
3f7a93a4df | |||
3e1a05763b | |||
45c7468e42 | |||
cda3622cb8 | |||
07f1505d6d | |||
e6f1e47a2c | |||
24034bf3d3 | |||
0eb3bf108e | |||
0e54e5181b | |||
d1fa9f1138 | |||
de2242eed7 | |||
bbbbdacf39 | |||
27af10e687 | |||
cb666041ec | |||
e08fe0daa0 | |||
05184e8276 | |||
5cf5e60918 |
@@ -49,6 +49,14 @@ struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
|
|||||||
int type,
|
int type,
|
||||||
AttributeDomain domain);
|
AttributeDomain domain);
|
||||||
|
|
||||||
|
/* Return an existing CustomDataLayer, or create a new one if none is found for the given
|
||||||
|
* parameters and return it. */
|
||||||
|
struct CustomDataLayer *BKE_id_attribute_ensure(struct ID *id,
|
||||||
|
const char *name,
|
||||||
|
const int type,
|
||||||
|
const AttributeDomain domain,
|
||||||
|
struct ReportList *reports);
|
||||||
|
|
||||||
AttributeDomain BKE_id_attribute_domain(struct ID *id, struct CustomDataLayer *layer);
|
AttributeDomain BKE_id_attribute_domain(struct ID *id, struct CustomDataLayer *layer);
|
||||||
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
|
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
|
||||||
bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);
|
bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);
|
||||||
@@ -65,6 +73,13 @@ int *BKE_id_attributes_active_index_p(struct ID *id);
|
|||||||
|
|
||||||
CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers);
|
CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers);
|
||||||
|
|
||||||
|
typedef struct DomainInfo {
|
||||||
|
CustomData *customdata;
|
||||||
|
int length;
|
||||||
|
} DomainInfo;
|
||||||
|
|
||||||
|
void BKE_id_attribute_get_domains(const struct ID *id, DomainInfo info[ATTR_DOMAIN_NUM]);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct CacheAttributeMapping;
|
||||||
struct CacheFile;
|
struct CacheFile;
|
||||||
struct CacheFileLayer;
|
struct CacheFileLayer;
|
||||||
struct CacheReader;
|
struct CacheReader;
|
||||||
@@ -63,6 +64,17 @@ struct CacheFileLayer *BKE_cachefile_get_active_layer(struct CacheFile *cache_fi
|
|||||||
|
|
||||||
void BKE_cachefile_remove_layer(struct CacheFile *cache_file, struct CacheFileLayer *layer);
|
void BKE_cachefile_remove_layer(struct CacheFile *cache_file, struct CacheFileLayer *layer);
|
||||||
|
|
||||||
|
struct CacheAttributeMapping *BKE_cachefile_add_attribute_mapping(struct CacheFile *cache_file,
|
||||||
|
const char *name,
|
||||||
|
int mapping_type,
|
||||||
|
int domain);
|
||||||
|
|
||||||
|
struct CacheAttributeMapping *BKE_cachefile_get_active_attribute_mapping(
|
||||||
|
struct CacheFile *cache_file);
|
||||||
|
|
||||||
|
void BKE_cachefile_remove_attribute_mapping(struct CacheFile *cache_file,
|
||||||
|
struct CacheAttributeMapping *mapping);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -601,6 +601,10 @@ void BKE_modifier_blend_read_data(struct BlendDataReader *reader,
|
|||||||
struct Object *ob);
|
struct Object *ob);
|
||||||
void BKE_modifier_blend_read_lib(struct BlendLibReader *reader, struct Object *ob);
|
void BKE_modifier_blend_read_lib(struct BlendLibReader *reader, struct Object *ob);
|
||||||
|
|
||||||
|
/* Return whether the modifier can operate directly on a Curve, i.e. without needing a conversion
|
||||||
|
* to a temporary Mesh. */
|
||||||
|
bool BKE_modifier_supports_curve_data(const ModifierData *md);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -25,6 +25,9 @@ extern const char *POINTCLOUD_ATTR_RADIUS;
|
|||||||
void *BKE_pointcloud_add(struct Main *bmain, const char *name);
|
void *BKE_pointcloud_add(struct Main *bmain, const char *name);
|
||||||
void *BKE_pointcloud_add_default(struct Main *bmain, const char *name);
|
void *BKE_pointcloud_add_default(struct Main *bmain, const char *name);
|
||||||
struct PointCloud *BKE_pointcloud_new_nomain(int totpoint);
|
struct PointCloud *BKE_pointcloud_new_nomain(int totpoint);
|
||||||
|
void BKE_pointcloud_nomain_to_pointcloud(struct PointCloud *pointcloud_src,
|
||||||
|
struct PointCloud *pointcloud_dst,
|
||||||
|
bool take_ownership);
|
||||||
|
|
||||||
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
|
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
|
||||||
bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
|
bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
|
||||||
|
@@ -29,12 +29,7 @@
|
|||||||
|
|
||||||
#include "RNA_access.h"
|
#include "RNA_access.h"
|
||||||
|
|
||||||
typedef struct DomainInfo {
|
void BKE_id_attribute_get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
|
||||||
CustomData *customdata;
|
|
||||||
int length;
|
|
||||||
} DomainInfo;
|
|
||||||
|
|
||||||
static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
|
|
||||||
{
|
{
|
||||||
memset(info, 0, sizeof(DomainInfo) * ATTR_DOMAIN_NUM);
|
memset(info, 0, sizeof(DomainInfo) * ATTR_DOMAIN_NUM);
|
||||||
|
|
||||||
@@ -87,7 +82,7 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
|
|||||||
static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
|
static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
||||||
CustomData *customdata = info[domain].customdata;
|
CustomData *customdata = info[domain].customdata;
|
||||||
@@ -102,7 +97,7 @@ static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
|
|||||||
bool BKE_id_attributes_supported(struct ID *id)
|
bool BKE_id_attributes_supported(struct ID *id)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
||||||
if (info[domain].customdata) {
|
if (info[domain].customdata) {
|
||||||
return true;
|
return true;
|
||||||
@@ -136,7 +131,7 @@ CustomDataLayer *BKE_id_attribute_new(
|
|||||||
ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
|
ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
CustomData *customdata = info[domain].customdata;
|
CustomData *customdata = info[domain].customdata;
|
||||||
if (customdata == NULL) {
|
if (customdata == NULL) {
|
||||||
@@ -212,7 +207,7 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
|
|||||||
const AttributeDomain domain)
|
const AttributeDomain domain)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
CustomData *customdata = info[domain].customdata;
|
CustomData *customdata = info[domain].customdata;
|
||||||
if (customdata == NULL) {
|
if (customdata == NULL) {
|
||||||
@@ -229,10 +224,22 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CustomDataLayer *BKE_id_attribute_ensure(
|
||||||
|
ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
|
||||||
|
{
|
||||||
|
CustomDataLayer *layer = BKE_id_attribute_find(id, name, type, domain);
|
||||||
|
|
||||||
|
if (layer) {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BKE_id_attribute_new(id, name, type, domain, reports);
|
||||||
|
}
|
||||||
|
|
||||||
int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
|
int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
int length = 0;
|
int length = 0;
|
||||||
|
|
||||||
@@ -249,7 +256,7 @@ int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
|
|||||||
AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer)
|
AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
||||||
CustomData *customdata = info[domain].customdata;
|
CustomData *customdata = info[domain].customdata;
|
||||||
@@ -265,7 +272,7 @@ AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer)
|
|||||||
int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
|
int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
||||||
CustomData *customdata = info[domain].customdata;
|
CustomData *customdata = info[domain].customdata;
|
||||||
@@ -300,7 +307,7 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
@@ -325,7 +332,7 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
|
|||||||
void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
|
void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
@@ -366,7 +373,7 @@ int *BKE_id_attributes_active_index_p(ID *id)
|
|||||||
CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *layers)
|
CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *layers)
|
||||||
{
|
{
|
||||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||||
get_domains(id, info);
|
BKE_id_attribute_get_domains(id, info);
|
||||||
|
|
||||||
bool use_next = (layers == NULL);
|
bool use_next = (layers == NULL);
|
||||||
|
|
||||||
|
@@ -73,6 +73,7 @@ static void cache_file_copy_data(Main *UNUSED(bmain),
|
|||||||
cache_file_dst->handle_readers = NULL;
|
cache_file_dst->handle_readers = NULL;
|
||||||
BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths);
|
BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths);
|
||||||
BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers);
|
BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers);
|
||||||
|
BLI_duplicatelist(&cache_file_dst->attribute_mappings, &cache_file_src->attribute_mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cache_file_free_data(ID *id)
|
static void cache_file_free_data(ID *id)
|
||||||
@@ -81,6 +82,7 @@ static void cache_file_free_data(ID *id)
|
|||||||
cachefile_handle_free(cache_file);
|
cachefile_handle_free(cache_file);
|
||||||
BLI_freelistN(&cache_file->object_paths);
|
BLI_freelistN(&cache_file->object_paths);
|
||||||
BLI_freelistN(&cache_file->layers);
|
BLI_freelistN(&cache_file->layers);
|
||||||
|
BLI_freelistN(&cache_file->attribute_mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
|
static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
|
||||||
@@ -110,6 +112,11 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a
|
|||||||
LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
|
LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
|
||||||
BLO_write_struct(writer, CacheFileLayer, layer);
|
BLO_write_struct(writer, CacheFileLayer, layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* write attribute mappings */
|
||||||
|
LISTBASE_FOREACH (CacheAttributeMapping *, mapping, &cache_file->attribute_mappings) {
|
||||||
|
BLO_write_struct(writer, CacheAttributeMapping, mapping);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
|
static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
|
||||||
@@ -126,6 +133,9 @@ static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
|
|||||||
|
|
||||||
/* relink layers */
|
/* relink layers */
|
||||||
BLO_read_list(reader, &cache_file->layers);
|
BLO_read_list(reader, &cache_file->layers);
|
||||||
|
|
||||||
|
/* relink attribute mappings */
|
||||||
|
BLO_read_list(reader, &cache_file->attribute_mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
IDTypeInfo IDType_ID_CF = {
|
IDTypeInfo IDType_ID_CF = {
|
||||||
@@ -464,3 +474,38 @@ void BKE_cachefile_remove_layer(CacheFile *cache_file, CacheFileLayer *layer)
|
|||||||
BLI_remlink(&cache_file->layers, layer);
|
BLI_remlink(&cache_file->layers, layer);
|
||||||
MEM_freeN(layer);
|
MEM_freeN(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CacheAttributeMapping *BKE_cachefile_add_attribute_mapping(CacheFile *cache_file,
|
||||||
|
const char *name,
|
||||||
|
const int mapping_type,
|
||||||
|
const int domain)
|
||||||
|
{
|
||||||
|
const int current_mapping_count = BLI_listbase_count(&cache_file->attribute_mappings);
|
||||||
|
|
||||||
|
CacheAttributeMapping *mapping = MEM_callocN(sizeof(CacheAttributeMapping),
|
||||||
|
"CacheAttributeMapping");
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
BLI_strncpy(mapping->name, name, sizeof(mapping->name));
|
||||||
|
}
|
||||||
|
mapping->mapping = (char)mapping_type;
|
||||||
|
mapping->domain = (char)domain;
|
||||||
|
|
||||||
|
BLI_addtail(&cache_file->attribute_mappings, mapping);
|
||||||
|
|
||||||
|
cache_file->active_attribute_mapping = current_mapping_count + 1;
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheAttributeMapping *BKE_cachefile_get_active_attribute_mapping(CacheFile *cache_file)
|
||||||
|
{
|
||||||
|
/* BLI_findlink handles the out of bounds checks. */
|
||||||
|
return BLI_findlink(&cache_file->attribute_mappings, cache_file->active_attribute_mapping - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_cachefile_remove_attribute_mapping(CacheFile *cache_file, CacheAttributeMapping *mapping)
|
||||||
|
{
|
||||||
|
cache_file->active_attribute_mapping = 0;
|
||||||
|
BLI_remlink(&cache_file->attribute_mappings, mapping);
|
||||||
|
MEM_freeN(mapping);
|
||||||
|
}
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include "BKE_anim_data.h"
|
#include "BKE_anim_data.h"
|
||||||
#include "BKE_curves.hh"
|
#include "BKE_curves.hh"
|
||||||
#include "BKE_customdata.h"
|
#include "BKE_customdata.h"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
#include "BKE_idtype.h"
|
#include "BKE_idtype.h"
|
||||||
#include "BKE_lib_id.h"
|
#include "BKE_lib_id.h"
|
||||||
@@ -308,8 +309,15 @@ static Curves *curves_evaluate_modifiers(struct Depsgraph *depsgraph,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mti->type == eModifierTypeType_OnlyDeform) &&
|
if (mti->modifyGeometrySet) {
|
||||||
(mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
|
GeometrySet geometry_set = GeometrySet::create_with_curves(curves,
|
||||||
|
GeometryOwnershipType::ReadOnly);
|
||||||
|
mti->modifyGeometrySet(md, &mectx, &geometry_set);
|
||||||
|
|
||||||
|
curves = geometry_set.get_component_for_write<CurveComponent>().release();
|
||||||
|
}
|
||||||
|
else if ((mti->type == eModifierTypeType_OnlyDeform) &&
|
||||||
|
(mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
|
||||||
/* Ensure we are not modifying the input. */
|
/* Ensure we are not modifying the input. */
|
||||||
if (curves == curves_input) {
|
if (curves == curves_input) {
|
||||||
curves = BKE_curves_copy_for_eval(curves, true);
|
curves = BKE_curves_copy_for_eval(curves, true);
|
||||||
|
@@ -812,12 +812,12 @@ static bool do_curve_implicit_mesh_conversion(const Curve *curve,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If a non-geometry-nodes modifier is enabled before a nodes modifier,
|
/* If a modifier which does not support curve data is enabled before one that does,
|
||||||
* force conversion to mesh, since only the nodes modifier supports curve data. */
|
* force conversion to mesh. */
|
||||||
ModifierData *md = first_modifier;
|
ModifierData *md = first_modifier;
|
||||||
for (; md; md = md->next) {
|
for (; md; md = md->next) {
|
||||||
if (BKE_modifier_is_enabled(scene, md, required_mode)) {
|
if (BKE_modifier_is_enabled(scene, md, required_mode)) {
|
||||||
if (md->type == eModifierType_Nodes) {
|
if (BKE_modifier_supports_curve_data(md)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -874,7 +874,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (md->type == eModifierType_Nodes) {
|
if (BKE_modifier_supports_curve_data(md)) {
|
||||||
mti->modifyGeometrySet(md, &mectx_apply, &geometry_set);
|
mti->modifyGeometrySet(md, &mectx_apply, &geometry_set);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
#include "DNA_armature_types.h"
|
#include "DNA_armature_types.h"
|
||||||
|
#include "DNA_cachefile_types.h"
|
||||||
#include "DNA_cloth_types.h"
|
#include "DNA_cloth_types.h"
|
||||||
#include "DNA_dynamicpaint_types.h"
|
#include "DNA_dynamicpaint_types.h"
|
||||||
#include "DNA_fluid_types.h"
|
#include "DNA_fluid_types.h"
|
||||||
@@ -1518,3 +1519,27 @@ void BKE_modifier_blend_read_lib(BlendLibReader *reader, Object *ob)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BKE_modifier_supports_curve_data(const ModifierData *md)
|
||||||
|
{
|
||||||
|
/* Sanity check. */
|
||||||
|
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
|
||||||
|
if (mti->modifyGeometrySet == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (md->type == eModifierType_Nodes) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the MeshSequenceCache, only the Alembic backend supports directly reading/modifying
|
||||||
|
* curves.
|
||||||
|
*/
|
||||||
|
if (md->type == eModifierType_MeshSequenceCache) {
|
||||||
|
MeshSeqCacheModifierData *msmd = (MeshSeqCacheModifierData *)md;
|
||||||
|
CacheFile *cache_file = msmd->cache_file;
|
||||||
|
return cache_file && cache_file->type == CACHEFILE_TYPE_ALEMBIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -255,6 +255,52 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
|
|||||||
return pointcloud;
|
return pointcloud;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src,
|
||||||
|
PointCloud *pointcloud_dst,
|
||||||
|
bool take_ownership)
|
||||||
|
{
|
||||||
|
BLI_assert(pointcloud_src->id.tag & LIB_TAG_NO_MAIN);
|
||||||
|
|
||||||
|
/* pointcloud_src might depend on pointcloud_dst, so we need to do everything with a local copy
|
||||||
|
*/
|
||||||
|
PointCloud tmp = *pointcloud_dst;
|
||||||
|
eCDAllocType alloctype = CD_DUPLICATE;
|
||||||
|
|
||||||
|
if (take_ownership) {
|
||||||
|
bool has_any_referenced_layers = CustomData_has_referenced(&pointcloud_src->pdata);
|
||||||
|
|
||||||
|
if (!has_any_referenced_layers) {
|
||||||
|
alloctype = CD_ASSIGN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomData_reset(&tmp.pdata);
|
||||||
|
|
||||||
|
const CustomDataMask pmask = CD_MASK_ALL;
|
||||||
|
|
||||||
|
const int totpoint = tmp.totpoint = pointcloud_src->totpoint;
|
||||||
|
CustomData_copy(&pointcloud_src->pdata, &tmp.pdata, pmask, alloctype, totpoint);
|
||||||
|
|
||||||
|
BKE_pointcloud_update_customdata_pointers(&tmp);
|
||||||
|
|
||||||
|
CustomData_free(&pointcloud_dst->pdata, pointcloud_dst->totpoint);
|
||||||
|
|
||||||
|
/* skip the listbase */
|
||||||
|
MEMCPY_STRUCT_AFTER(pointcloud_dst, &tmp, id.prev);
|
||||||
|
|
||||||
|
if (take_ownership) {
|
||||||
|
if (alloctype == CD_ASSIGN) {
|
||||||
|
CustomData_free_typemask(&pointcloud_src->pdata, pointcloud_src->totpoint, ~pmask);
|
||||||
|
}
|
||||||
|
BKE_id_free(nullptr, pointcloud_src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MinMaxResult {
|
||||||
|
float3 min;
|
||||||
|
float3 max;
|
||||||
|
};
|
||||||
|
|
||||||
static std::optional<blender::bounds::MinMaxResult<float3>> point_cloud_bounds(
|
static std::optional<blender::bounds::MinMaxResult<float3>> point_cloud_bounds(
|
||||||
const PointCloud &pointcloud)
|
const PointCloud &pointcloud)
|
||||||
{
|
{
|
||||||
|
@@ -2419,6 +2419,13 @@ void uiTemplateCacheFileLayers(uiLayout *layout,
|
|||||||
const struct bContext *C,
|
const struct bContext *C,
|
||||||
struct PointerRNA *fileptr);
|
struct PointerRNA *fileptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the attribute remapping related properties of the CacheFile.
|
||||||
|
*/
|
||||||
|
void uiTemplateCacheFileAttributeRemapping(uiLayout *layout,
|
||||||
|
const struct bContext *C,
|
||||||
|
struct PointerRNA *fileptr);
|
||||||
|
|
||||||
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
|
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
|
||||||
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
|
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
|
||||||
enum uiTemplateListFlags {
|
enum uiTemplateListFlags {
|
||||||
|
@@ -1477,6 +1477,9 @@ void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
|
|||||||
|
|
||||||
struct uiListType *UI_UL_asset_view(void);
|
struct uiListType *UI_UL_asset_view(void);
|
||||||
|
|
||||||
|
/* interface_templates.c */
|
||||||
|
struct uiListType *UI_UL_cache_file_attribute_mappings(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For use with #ui_rna_collection_search_update_fn.
|
* For use with #ui_rna_collection_search_update_fn.
|
||||||
*/
|
*/
|
||||||
|
@@ -1309,6 +1309,7 @@ void ED_uilisttypes_ui()
|
|||||||
{
|
{
|
||||||
WM_uilisttype_add(UI_UL_asset_view());
|
WM_uilisttype_add(UI_UL_asset_view());
|
||||||
WM_uilisttype_add(UI_UL_cache_file_layers());
|
WM_uilisttype_add(UI_UL_cache_file_layers());
|
||||||
|
WM_uilisttype_add(UI_UL_cache_file_attribute_mappings());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@@ -6505,6 +6505,63 @@ bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRN
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cache_file_attribute_mapping_item(uiList *UNUSED(ui_list),
|
||||||
|
bContext *UNUSED(C),
|
||||||
|
uiLayout *layout,
|
||||||
|
PointerRNA *UNUSED(dataptr),
|
||||||
|
PointerRNA *itemptr,
|
||||||
|
int UNUSED(icon),
|
||||||
|
PointerRNA *UNUSED(active_dataptr),
|
||||||
|
const char *UNUSED(active_propname),
|
||||||
|
int UNUSED(index),
|
||||||
|
int UNUSED(flt_flag))
|
||||||
|
{
|
||||||
|
uiLayout *row = uiLayoutRow(layout, true);
|
||||||
|
uiItemR(row, itemptr, "name", UI_ITEM_R_NO_BG, "", ICON_NONE);
|
||||||
|
uiItemR(row, itemptr, "mapping", UI_ITEM_R_NO_BG, "", ICON_NONE);
|
||||||
|
uiItemR(row, itemptr, "domain", UI_ITEM_R_NO_BG, "", ICON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
uiListType *UI_UL_cache_file_attribute_mappings()
|
||||||
|
{
|
||||||
|
uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__);
|
||||||
|
|
||||||
|
BLI_strncpy(list_type->idname, "UI_UL_cache_file_attribute_mappings", sizeof(list_type->idname));
|
||||||
|
list_type->draw_item = cache_file_attribute_mapping_item;
|
||||||
|
|
||||||
|
return list_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiTemplateCacheFileAttributeRemapping(uiLayout *layout,
|
||||||
|
const bContext *C,
|
||||||
|
PointerRNA *fileptr)
|
||||||
|
{
|
||||||
|
/* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
|
||||||
|
uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
|
||||||
|
|
||||||
|
uiLayout *row = uiLayoutRow(layout, false);
|
||||||
|
uiLayout *col = uiLayoutColumn(row, true);
|
||||||
|
|
||||||
|
uiTemplateList(col,
|
||||||
|
(bContext *)C,
|
||||||
|
"UI_UL_cache_file_attribute_mappings",
|
||||||
|
"cache_file_attribute_mappings",
|
||||||
|
fileptr,
|
||||||
|
"attribute_mappings",
|
||||||
|
fileptr,
|
||||||
|
"active_attribute_mapping_index",
|
||||||
|
"",
|
||||||
|
1,
|
||||||
|
5,
|
||||||
|
UILST_LAYOUT_DEFAULT,
|
||||||
|
1,
|
||||||
|
UI_TEMPLATE_LIST_FLAG_NONE);
|
||||||
|
|
||||||
|
col = uiLayoutColumn(row, true);
|
||||||
|
uiItemO(col, "", ICON_ADD, "cachefile.attribute_mapping_add");
|
||||||
|
uiItemO(col, "", ICON_REMOVE, "cachefile.attribute_mapping_remove");
|
||||||
|
}
|
||||||
|
|
||||||
void uiTemplateCacheFile(uiLayout *layout,
|
void uiTemplateCacheFile(uiLayout *layout,
|
||||||
const bContext *C,
|
const bContext *C,
|
||||||
PointerRNA *ptr,
|
PointerRNA *ptr,
|
||||||
|
@@ -312,3 +312,78 @@ void CACHEFILE_OT_layer_move(wmOperatorType *ot)
|
|||||||
"Direction",
|
"Direction",
|
||||||
"Direction to move the active vertex group towards");
|
"Direction to move the active vertex group towards");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ***************************** Add Attribute Mapping Operator **************************** */
|
||||||
|
|
||||||
|
static bool cachefile_attribute_mapping_poll(bContext *C)
|
||||||
|
{
|
||||||
|
return CTX_data_edit_cachefile(C) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cachefile_attribute_mapping_add_exec(bContext *C, wmOperator *UNUSED(op))
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||||
|
|
||||||
|
if (!cache_file) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_cachefile_add_attribute_mapping(
|
||||||
|
cache_file, NULL, CACHEFILE_ATTRIBUTE_MAP_NONE, CACHEFILE_ATTR_MAP_DOMAIN_AUTO);
|
||||||
|
|
||||||
|
/* Since the mapping is not initialized, adding a mapping does not trigger a CacheFile update. */
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CACHEFILE_OT_attribute_mapping_add(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
ot->name = "Add Attribute Mapping";
|
||||||
|
ot->description = "Add an attribute mapping for this CacheFile";
|
||||||
|
ot->idname = __func__;
|
||||||
|
|
||||||
|
/* api callbacks */
|
||||||
|
ot->exec = cachefile_attribute_mapping_add_exec;
|
||||||
|
ot->poll = cachefile_attribute_mapping_poll;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ***************************** Remove Attribute Mapping Operator **************************** */
|
||||||
|
|
||||||
|
static int cachefile_attribute_mapping_remove_exec(bContext *C, wmOperator *UNUSED(op))
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||||
|
|
||||||
|
if (!cache_file) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheAttributeMapping *mapping = BKE_cachefile_get_active_attribute_mapping(cache_file);
|
||||||
|
|
||||||
|
if (!mapping) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_cachefile_remove_attribute_mapping(cache_file, mapping);
|
||||||
|
|
||||||
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||||
|
BKE_cachefile_reload(depsgraph, cache_file);
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CACHEFILE_OT_attribute_mapping_remove(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
ot->name = "Remove Attribute Mapping";
|
||||||
|
ot->description = "Remove an attribute mapping from this CacheFile";
|
||||||
|
ot->idname = __func__;
|
||||||
|
|
||||||
|
/* api callbacks */
|
||||||
|
ot->exec = cachefile_attribute_mapping_remove_exec;
|
||||||
|
ot->poll = cachefile_attribute_mapping_poll;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
}
|
||||||
|
@@ -15,3 +15,6 @@ void CACHEFILE_OT_reload(struct wmOperatorType *ot);
|
|||||||
void CACHEFILE_OT_layer_add(struct wmOperatorType *ot);
|
void CACHEFILE_OT_layer_add(struct wmOperatorType *ot);
|
||||||
void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot);
|
void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot);
|
||||||
void CACHEFILE_OT_layer_move(struct wmOperatorType *ot);
|
void CACHEFILE_OT_layer_move(struct wmOperatorType *ot);
|
||||||
|
|
||||||
|
void CACHEFILE_OT_attribute_mapping_add(struct wmOperatorType *ot);
|
||||||
|
void CACHEFILE_OT_attribute_mapping_remove(struct wmOperatorType *ot);
|
||||||
|
@@ -58,5 +58,8 @@ void ED_operatortypes_io(void)
|
|||||||
WM_operatortype_append(CACHEFILE_OT_layer_remove);
|
WM_operatortype_append(CACHEFILE_OT_layer_remove);
|
||||||
WM_operatortype_append(CACHEFILE_OT_layer_move);
|
WM_operatortype_append(CACHEFILE_OT_layer_move);
|
||||||
|
|
||||||
|
WM_operatortype_append(CACHEFILE_OT_attribute_mapping_add);
|
||||||
|
WM_operatortype_append(CACHEFILE_OT_attribute_mapping_remove);
|
||||||
|
|
||||||
WM_operatortype_append(WM_OT_obj_export);
|
WM_operatortype_append(WM_OT_obj_export);
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,8 @@ extern "C" {
|
|||||||
struct CacheArchiveHandle;
|
struct CacheArchiveHandle;
|
||||||
struct CacheFileLayer;
|
struct CacheFileLayer;
|
||||||
struct CacheReader;
|
struct CacheReader;
|
||||||
|
struct Curves;
|
||||||
|
struct GeometrySet;
|
||||||
struct ListBase;
|
struct ListBase;
|
||||||
struct Main;
|
struct Main;
|
||||||
struct Mesh;
|
struct Mesh;
|
||||||
@@ -99,15 +101,23 @@ void ABC_get_transform(struct CacheReader *reader,
|
|||||||
float time,
|
float time,
|
||||||
float scale);
|
float scale);
|
||||||
|
|
||||||
/* Either modifies existing_mesh in-place or constructs a new mesh. */
|
typedef struct ABCReadParams {
|
||||||
struct Mesh *ABC_read_mesh(struct CacheReader *reader,
|
float time;
|
||||||
struct Object *ob,
|
int read_flags;
|
||||||
struct Mesh *existing_mesh,
|
const char *velocity_name;
|
||||||
float time,
|
float velocity_scale;
|
||||||
const char **err_str,
|
|
||||||
int read_flags,
|
ListBase *mappings;
|
||||||
const char *velocity_name,
|
} ABCReadParams;
|
||||||
float velocity_scale);
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
/* Either modifies the existing geometry component, or create a new one. */
|
||||||
|
void ABC_read_geometry(CacheReader *reader,
|
||||||
|
Object *ob,
|
||||||
|
GeometrySet &geometry_set,
|
||||||
|
const ABCReadParams *params,
|
||||||
|
const char **err_str);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool ABC_mesh_topology_changed(struct CacheReader *reader,
|
bool ABC_mesh_topology_changed(struct CacheReader *reader,
|
||||||
struct Object *ob,
|
struct Object *ob,
|
||||||
|
@@ -7,9 +7,11 @@ set(INC
|
|||||||
../../blenkernel
|
../../blenkernel
|
||||||
../../blenlib
|
../../blenlib
|
||||||
../../blenloader
|
../../blenloader
|
||||||
|
../../blentranslation
|
||||||
../../bmesh
|
../../bmesh
|
||||||
../../depsgraph
|
../../depsgraph
|
||||||
../../editors/include
|
../../editors/include
|
||||||
|
../../functions
|
||||||
../../makesdna
|
../../makesdna
|
||||||
../../makesrna
|
../../makesrna
|
||||||
../../windowmanager
|
../../windowmanager
|
||||||
@@ -30,6 +32,8 @@ set(SRC
|
|||||||
intern/abc_reader_archive.cc
|
intern/abc_reader_archive.cc
|
||||||
intern/abc_reader_camera.cc
|
intern/abc_reader_camera.cc
|
||||||
intern/abc_reader_curves.cc
|
intern/abc_reader_curves.cc
|
||||||
|
intern/abc_reader_instance.cc
|
||||||
|
intern/abc_reader_manager.cc
|
||||||
intern/abc_reader_mesh.cc
|
intern/abc_reader_mesh.cc
|
||||||
intern/abc_reader_nurbs.cc
|
intern/abc_reader_nurbs.cc
|
||||||
intern/abc_reader_object.cc
|
intern/abc_reader_object.cc
|
||||||
@@ -60,6 +64,8 @@ set(SRC
|
|||||||
intern/abc_reader_archive.h
|
intern/abc_reader_archive.h
|
||||||
intern/abc_reader_camera.h
|
intern/abc_reader_camera.h
|
||||||
intern/abc_reader_curves.h
|
intern/abc_reader_curves.h
|
||||||
|
intern/abc_reader_instance.h
|
||||||
|
intern/abc_reader_manager.h
|
||||||
intern/abc_reader_mesh.h
|
intern/abc_reader_mesh.h
|
||||||
intern/abc_reader_nurbs.h
|
intern/abc_reader_nurbs.h
|
||||||
intern/abc_reader_object.h
|
intern/abc_reader_object.h
|
||||||
|
@@ -76,6 +76,12 @@ static void get_loop_normals(struct Mesh *mesh,
|
|||||||
ABCGenericMeshWriter::ABCGenericMeshWriter(const ABCWriterConstructorArgs &args)
|
ABCGenericMeshWriter::ABCGenericMeshWriter(const ABCWriterConstructorArgs &args)
|
||||||
: ABCAbstractWriter(args), is_subd_(false)
|
: ABCAbstractWriter(args), is_subd_(false)
|
||||||
{
|
{
|
||||||
|
attribute_exporter_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ABCGenericMeshWriter::~ABCGenericMeshWriter()
|
||||||
|
{
|
||||||
|
delete_attribute_exporter(attribute_exporter_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABCGenericMeshWriter::create_alembic_objects(const HierarchyContext *context)
|
void ABCGenericMeshWriter::create_alembic_objects(const HierarchyContext *context)
|
||||||
@@ -254,10 +260,6 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
|
|||||||
mesh_sample.setNormals(normals_sample);
|
mesh_sample.setNormals(normals_sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_.export_params->orcos) {
|
|
||||||
write_generated_coordinates(abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_velocities(mesh, velocities)) {
|
if (get_velocities(mesh, velocities)) {
|
||||||
mesh_sample.setVelocities(V3fArraySample(velocities));
|
mesh_sample.setVelocities(V3fArraySample(velocities));
|
||||||
}
|
}
|
||||||
@@ -266,7 +268,6 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
|
|||||||
mesh_sample.setSelfBounds(bounding_box_);
|
mesh_sample.setSelfBounds(bounding_box_);
|
||||||
|
|
||||||
abc_poly_mesh_schema_.set(mesh_sample);
|
abc_poly_mesh_schema_.set(mesh_sample);
|
||||||
|
|
||||||
write_arb_geo_params(mesh);
|
write_arb_geo_params(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,10 +309,6 @@ void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *me
|
|||||||
abc_subdiv_schema_.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV);
|
abc_subdiv_schema_.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_.export_params->orcos) {
|
|
||||||
write_generated_coordinates(abc_subdiv_schema_.getArbGeomParams(), m_custom_data_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!edge_crease_indices.empty()) {
|
if (!edge_crease_indices.empty()) {
|
||||||
subdiv_sample.setCreaseIndices(Int32ArraySample(edge_crease_indices));
|
subdiv_sample.setCreaseIndices(Int32ArraySample(edge_crease_indices));
|
||||||
subdiv_sample.setCreaseLengths(Int32ArraySample(edge_crease_lengths));
|
subdiv_sample.setCreaseLengths(Int32ArraySample(edge_crease_lengths));
|
||||||
@@ -347,8 +344,15 @@ void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Sc
|
|||||||
|
|
||||||
void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
|
void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
|
||||||
{
|
{
|
||||||
|
int64_t cd_mask = CD_MASK_ALL;
|
||||||
if (!args_.export_params->vcolors) {
|
if (!args_.export_params->vcolors) {
|
||||||
return;
|
cd_mask &= ~CD_MASK_MCOL;
|
||||||
|
}
|
||||||
|
if (!args_.export_params->uvs) {
|
||||||
|
cd_mask &= ~CD_MASK_MLOOPUV;
|
||||||
|
}
|
||||||
|
if (!args_.export_params->orcos) {
|
||||||
|
cd_mask &= ~CD_MASK_ORCO;
|
||||||
}
|
}
|
||||||
|
|
||||||
OCompoundProperty arb_geom_params;
|
OCompoundProperty arb_geom_params;
|
||||||
@@ -358,7 +362,13 @@ void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
|
|||||||
else {
|
else {
|
||||||
arb_geom_params = abc_poly_mesh_.getSchema().getArbGeomParams();
|
arb_geom_params = abc_poly_mesh_.getSchema().getArbGeomParams();
|
||||||
}
|
}
|
||||||
write_custom_data(arb_geom_params, m_custom_data_config, &me->ldata, CD_MLOOPCOL);
|
|
||||||
|
if (!attribute_exporter_) {
|
||||||
|
attribute_exporter_ = make_attribute_exporter(&me->id, cd_mask, arb_geom_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_timesample_index(attribute_exporter_, m_custom_data_config.timesample_index);
|
||||||
|
attribute_exporter_->export_attributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ABCGenericMeshWriter::get_velocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels)
|
bool ABCGenericMeshWriter::get_velocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels)
|
||||||
|
@@ -34,9 +34,13 @@ class ABCGenericMeshWriter : public ABCAbstractWriter {
|
|||||||
|
|
||||||
CDStreamConfig m_custom_data_config;
|
CDStreamConfig m_custom_data_config;
|
||||||
|
|
||||||
|
GenericAttributeExporter *attribute_exporter_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ABCGenericMeshWriter(const ABCWriterConstructorArgs &args);
|
explicit ABCGenericMeshWriter(const ABCWriterConstructorArgs &args);
|
||||||
|
|
||||||
|
~ABCGenericMeshWriter();
|
||||||
|
|
||||||
virtual void create_alembic_objects(const HierarchyContext *context) override;
|
virtual void create_alembic_objects(const HierarchyContext *context) override;
|
||||||
virtual Alembic::Abc::OObject get_alembic_object() const override;
|
virtual Alembic::Abc::OObject get_alembic_object() const override;
|
||||||
Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
|
Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -11,17 +11,29 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "BKE_attribute.h"
|
||||||
|
|
||||||
|
#include "BLI_color.hh"
|
||||||
|
#include "BLI_listbase_wrapper.hh"
|
||||||
|
#include "BLI_math_vec_types.hh"
|
||||||
|
#include "BLI_span.hh"
|
||||||
|
|
||||||
|
struct CacheAttributeMapping;
|
||||||
struct CustomData;
|
struct CustomData;
|
||||||
|
struct ID;
|
||||||
struct MLoop;
|
struct MLoop;
|
||||||
struct MLoopUV;
|
struct MLoopUV;
|
||||||
struct MPoly;
|
struct MPoly;
|
||||||
struct MVert;
|
struct MVert;
|
||||||
struct Mesh;
|
struct Mesh;
|
||||||
|
struct MCol;
|
||||||
|
|
||||||
using Alembic::Abc::ICompoundProperty;
|
using Alembic::Abc::ICompoundProperty;
|
||||||
using Alembic::Abc::OCompoundProperty;
|
using Alembic::Abc::OCompoundProperty;
|
||||||
namespace blender::io::alembic {
|
namespace blender::io::alembic {
|
||||||
|
|
||||||
|
class AttributeSelector;
|
||||||
|
|
||||||
struct UVSample {
|
struct UVSample {
|
||||||
std::vector<Imath::V2f> uvs;
|
std::vector<Imath::V2f> uvs;
|
||||||
std::vector<uint32_t> indices;
|
std::vector<uint32_t> indices;
|
||||||
@@ -43,10 +55,12 @@ struct CDStreamConfig {
|
|||||||
|
|
||||||
bool pack_uvs;
|
bool pack_uvs;
|
||||||
|
|
||||||
/* TODO(kevin): might need a better way to handle adding and/or updating
|
/* NOTE: the mesh is mostly used for iterating over loops for loop attributes (UVs, MCol, etc.).
|
||||||
* custom data such that it updates the custom data holder and its pointers properly. */
|
* It would be nice to remove it, in favor of a more generic way to iterate valid attribute
|
||||||
|
* indices.
|
||||||
|
*/
|
||||||
Mesh *mesh;
|
Mesh *mesh;
|
||||||
void *(*add_customdata_cb)(Mesh *mesh, const char *name, int data_type);
|
ID *id;
|
||||||
|
|
||||||
float weight;
|
float weight;
|
||||||
float time;
|
float time;
|
||||||
@@ -57,6 +71,13 @@ struct CDStreamConfig {
|
|||||||
|
|
||||||
const char **modifier_error_message;
|
const char **modifier_error_message;
|
||||||
|
|
||||||
|
DomainInfo domain_info[ATTR_DOMAIN_NUM];
|
||||||
|
|
||||||
|
/* For error reporting when reading vertex colors. */
|
||||||
|
std::string iobject_full_name;
|
||||||
|
|
||||||
|
const AttributeSelector *attr_selector;
|
||||||
|
|
||||||
/* Alembic needs Blender to keep references to C++ objects (the destructors finalize the writing
|
/* Alembic needs Blender to keep references to C++ objects (the destructors finalize the writing
|
||||||
* to ABC). The following fields are all used to keep these references. */
|
* to ABC). The following fields are all used to keep these references. */
|
||||||
|
|
||||||
@@ -78,12 +99,12 @@ struct CDStreamConfig {
|
|||||||
totvert(0),
|
totvert(0),
|
||||||
pack_uvs(false),
|
pack_uvs(false),
|
||||||
mesh(NULL),
|
mesh(NULL),
|
||||||
add_customdata_cb(NULL),
|
|
||||||
weight(0.0f),
|
weight(0.0f),
|
||||||
time(0.0f),
|
time(0.0f),
|
||||||
index(0),
|
index(0),
|
||||||
ceil_index(0),
|
ceil_index(0),
|
||||||
modifier_error_message(NULL)
|
modifier_error_message(NULL),
|
||||||
|
attr_selector(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -94,38 +115,126 @@ struct CDStreamConfig {
|
|||||||
* For now the active layer is used, maybe needs a better way to choose this. */
|
* For now the active layer is used, maybe needs a better way to choose this. */
|
||||||
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
|
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
|
||||||
|
|
||||||
void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config);
|
|
||||||
|
|
||||||
void read_generated_coordinates(const ICompoundProperty &prop,
|
|
||||||
const CDStreamConfig &config,
|
|
||||||
const Alembic::Abc::ISampleSelector &iss);
|
|
||||||
|
|
||||||
void write_custom_data(const OCompoundProperty &prop,
|
void write_custom_data(const OCompoundProperty &prop,
|
||||||
CDStreamConfig &config,
|
CDStreamConfig &config,
|
||||||
CustomData *data,
|
CustomData *data,
|
||||||
int data_type);
|
int data_type);
|
||||||
|
|
||||||
void read_custom_data(const std::string &iobject_full_name,
|
/* Need special handling for:
|
||||||
const ICompoundProperty &prop,
|
* - creases (vertex/edge)
|
||||||
const CDStreamConfig &config,
|
* - velocity
|
||||||
const Alembic::Abc::ISampleSelector &iss);
|
* - generated coordinate
|
||||||
|
* - UVs
|
||||||
typedef enum {
|
* - vertex colors
|
||||||
ABC_UV_SCOPE_NONE,
|
|
||||||
ABC_UV_SCOPE_LOOP,
|
|
||||||
ABC_UV_SCOPE_VERTEX,
|
|
||||||
} AbcUvScope;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
|
|
||||||
* vertex). The first case is the most common, as this is the standard way of storing this data
|
|
||||||
* given that some vertices might be on UV seams and have multiple possible UV coordinates; the
|
|
||||||
* second case can happen when the mesh is split according to the UV islands, in which case storing
|
|
||||||
* a single UV value per vertex allows to de-duplicate data and thus to reduce the file size since
|
|
||||||
* vertices are guaranteed to only have a single UV coordinate.
|
|
||||||
*/
|
*/
|
||||||
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
|
class GenericAttributeExporter {
|
||||||
const CDStreamConfig &config,
|
ID *m_id;
|
||||||
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices);
|
int64_t cd_mask = CD_MASK_ALL;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GenericAttributeExporter(ID *id, int64_t cd_mask_) : m_id(id), cd_mask(cd_mask_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_attributes();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void export_attribute(blender::Span<bool> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
virtual void export_attribute(blender::Span<char> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
virtual void export_attribute(blender::Span<int> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
virtual void export_attribute(blender::Span<float> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
virtual void export_attribute(blender::Span<float2> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
virtual void export_attribute(blender::Span<float3> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
virtual void export_attribute(blender::Span<ColorGeometry4f> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
virtual void export_attribute(blender::Span<MLoopUV> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
virtual void export_attribute(blender::Span<MCol> span,
|
||||||
|
const std::string &name,
|
||||||
|
AttributeDomain domain) = 0;
|
||||||
|
|
||||||
|
template<typename BlenderDataType>
|
||||||
|
void export_customdata_layer(CustomDataLayer *layer, DomainInfo info, AttributeDomain domain)
|
||||||
|
{
|
||||||
|
BlenderDataType *data = static_cast<BlenderDataType *>(layer->data);
|
||||||
|
int64_t size = static_cast<int64_t>(info.length);
|
||||||
|
blender::Span<BlenderDataType> data_span(data, size);
|
||||||
|
this->export_attribute(data_span, layer->name, domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_generated_coordinates(CustomDataLayer *layer,
|
||||||
|
DomainInfo info,
|
||||||
|
AttributeDomain domain);
|
||||||
|
|
||||||
|
void export_attribute_for_domain(DomainInfo info, AttributeDomain domain);
|
||||||
|
};
|
||||||
|
|
||||||
|
GenericAttributeExporter *make_attribute_exporter(ID *id,
|
||||||
|
int64_t cd_mask,
|
||||||
|
OCompoundProperty &prop);
|
||||||
|
|
||||||
|
void set_timesample_index(GenericAttributeExporter *exporter, int timesample_index);
|
||||||
|
|
||||||
|
void delete_attribute_exporter(GenericAttributeExporter *exporter);
|
||||||
|
|
||||||
|
class AttributeSelector {
|
||||||
|
/* Name of the velocity attribute, it is ignored since we deal with separately. */
|
||||||
|
std::string velocity_attribute = "";
|
||||||
|
|
||||||
|
int read_flags = 0;
|
||||||
|
|
||||||
|
ListBaseWrapper<const CacheAttributeMapping> mappings;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AttributeSelector(ListBase *mappings_) : mappings(mappings_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_velocity_attribute(const char *name);
|
||||||
|
|
||||||
|
void set_read_flags(int flags);
|
||||||
|
|
||||||
|
const CacheAttributeMapping *get_mapping(const std::string &attr_name) const;
|
||||||
|
|
||||||
|
const std::string &velocity_name() const;
|
||||||
|
|
||||||
|
bool uvs_requested() const;
|
||||||
|
|
||||||
|
bool vertex_colors_requested() const;
|
||||||
|
|
||||||
|
bool original_coordinates_requested() const;
|
||||||
|
|
||||||
|
bool select_attribute(const std::string &attr_name) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
void read_arbitrary_attributes(const CDStreamConfig &config,
|
||||||
|
const ICompoundProperty &schema,
|
||||||
|
const Alembic::AbcGeom::IV2fGeomParam &primary_uvs,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
|
float velocity_scale);
|
||||||
|
|
||||||
|
bool has_animated_attributes(const ICompoundProperty &arb_geom_params);
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
@@ -59,7 +59,9 @@ bool AbcCameraReader::accepts_object_type(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcCameraReader::readObjectData(Main *bmain, const ISampleSelector &sample_sel)
|
void AbcCameraReader::readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager & /*manager*/,
|
||||||
|
const ISampleSelector &sample_sel)
|
||||||
{
|
{
|
||||||
Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str()));
|
Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str()));
|
||||||
|
|
||||||
|
@@ -20,7 +20,9 @@ class AbcCameraReader final : public AbcObjectReader {
|
|||||||
const Object *const ob,
|
const Object *const ob,
|
||||||
const char **err_str) const override;
|
const char **err_str) const override;
|
||||||
|
|
||||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "abc_reader_curves.h"
|
#include "abc_reader_curves.h"
|
||||||
#include "abc_axis_conversion.h"
|
#include "abc_axis_conversion.h"
|
||||||
|
#include "abc_customdata.h"
|
||||||
#include "abc_reader_transform.h"
|
#include "abc_reader_transform.h"
|
||||||
#include "abc_util.h"
|
#include "abc_util.h"
|
||||||
|
|
||||||
@@ -14,14 +15,17 @@
|
|||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
#include "DNA_curve_types.h"
|
#include "DNA_curves_types.h"
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
|
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
|
|
||||||
#include "BKE_curve.h"
|
#include "BKE_curves.h"
|
||||||
|
#include "BKE_curves.hh"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
#include "BKE_object.h"
|
#include "BKE_object.h"
|
||||||
|
#include "BKE_spline.hh"
|
||||||
|
|
||||||
using Alembic::Abc::FloatArraySamplePtr;
|
using Alembic::Abc::FloatArraySamplePtr;
|
||||||
using Alembic::Abc::Int32ArraySamplePtr;
|
using Alembic::Abc::Int32ArraySamplePtr;
|
||||||
@@ -66,7 +70,7 @@ bool AbcCurveReader::accepts_object_type(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ob->type != OB_CURVES_LEGACY) {
|
if (ob->type != OB_CURVES) {
|
||||||
*err_str = "Object type mismatch, Alembic object path points to Curves.";
|
*err_str = "Object type mismatch, Alembic object path points to Curves.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -74,36 +78,234 @@ bool AbcCurveReader::accepts_object_type(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
void AbcCurveReader::readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager & /*manager*/,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||||
{
|
{
|
||||||
Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVES_LEGACY);
|
Curves *curves = static_cast<Curves *>(BKE_curves_add(bmain, m_data_name.c_str()));
|
||||||
|
|
||||||
cu->flag |= CU_3D;
|
m_object = BKE_object_add_only_object(bmain, OB_CURVES, m_object_name.c_str());
|
||||||
cu->actvert = CU_ACT_NONE;
|
m_object->data = curves;
|
||||||
cu->resolu = 1;
|
|
||||||
|
|
||||||
ICompoundProperty user_props = m_curves_schema.getUserProperties();
|
read_curves_sample(curves, m_curves_schema, sample_sel);
|
||||||
if (user_props) {
|
|
||||||
const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
|
|
||||||
if (header != nullptr && header->isScalar() && IInt16Property::matches(*header)) {
|
|
||||||
IInt16Property resolu(user_props, header->getName());
|
|
||||||
cu->resolu = resolu.getValue(sample_sel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_object = BKE_object_add_only_object(bmain, OB_CURVES_LEGACY, m_object_name.c_str());
|
|
||||||
m_object->data = cu;
|
|
||||||
|
|
||||||
read_curve_sample(cu, m_curves_schema, sample_sel);
|
|
||||||
|
|
||||||
if (m_settings->always_add_cache_reader || has_animations(m_curves_schema, m_settings)) {
|
if (m_settings->always_add_cache_reader || has_animations(m_curves_schema, m_settings)) {
|
||||||
addCacheModifier();
|
addCacheModifier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcCurveReader::read_curve_sample(Curve *cu,
|
static short get_curve_resolution(const ICurvesSchema &schema,
|
||||||
const ICurvesSchema &schema,
|
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||||
const ISampleSelector &sample_sel)
|
{
|
||||||
|
ICompoundProperty user_props = schema.getUserProperties();
|
||||||
|
if (user_props) {
|
||||||
|
const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
|
||||||
|
if (header != nullptr && header->isScalar() && IInt16Property::matches(*header)) {
|
||||||
|
IInt16Property resolu(user_props, header->getName());
|
||||||
|
return resolu.getValue(sample_sel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static short get_curve_order(Alembic::AbcGeom::CurveType abc_curve_type,
|
||||||
|
const UcharArraySamplePtr orders,
|
||||||
|
size_t curve_index)
|
||||||
|
{
|
||||||
|
switch (abc_curve_type) {
|
||||||
|
case Alembic::AbcGeom::kCubic:
|
||||||
|
return 4;
|
||||||
|
case Alembic::AbcGeom::kVariableOrder:
|
||||||
|
if (orders && orders->size() > curve_index) {
|
||||||
|
return static_cast<short>((*orders)[curve_index]);
|
||||||
|
}
|
||||||
|
ATTR_FALLTHROUGH;
|
||||||
|
case Alembic::AbcGeom::kLinear:
|
||||||
|
default:
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_curve_overlap(Alembic::AbcGeom::CurvePeriodicity periodicity,
|
||||||
|
const P3fArraySamplePtr positions,
|
||||||
|
int idx,
|
||||||
|
int num_verts,
|
||||||
|
short order)
|
||||||
|
{
|
||||||
|
if (periodicity == Alembic::AbcGeom::kPeriodic) {
|
||||||
|
/* Check the number of points which overlap, we don't have
|
||||||
|
* overlapping points in Blender, but other software do use them to
|
||||||
|
* indicate that a curve is actually cyclic. Usually the number of
|
||||||
|
* overlapping points is equal to the order/degree of the curve.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const int start = idx;
|
||||||
|
const int end = idx + num_verts;
|
||||||
|
int overlap = 0;
|
||||||
|
|
||||||
|
for (int j = start, k = end - order; j < order; j++, k++) {
|
||||||
|
const Imath::V3f &p1 = (*positions)[j];
|
||||||
|
const Imath::V3f &p2 = (*positions)[k];
|
||||||
|
|
||||||
|
if (p1 != p2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
overlap++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Special case, need to figure out how it coincides with knots. */
|
||||||
|
if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
|
||||||
|
overlap = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no real cycles. */
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* kNonPeriodic is always assumed to have no overlap. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int abc_curves_get_total_point_size(const Int32ArraySamplePtr num_vertices)
|
||||||
|
{
|
||||||
|
if (!num_vertices) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
for (size_t i = 0; i < num_vertices->size(); i++) {
|
||||||
|
result += (*num_vertices)[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_curves_sample_ex(Curves *curves,
|
||||||
|
const ICurvesSchema &schema,
|
||||||
|
const ICurvesSchema::Sample &smp,
|
||||||
|
const ISampleSelector sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
|
const float velocity_scale,
|
||||||
|
const char **err_str)
|
||||||
|
{
|
||||||
|
bke::CurvesGeometry &geometry = bke::CurvesGeometry::wrap(curves->geometry);
|
||||||
|
MutableSpan<int> offsets = geometry.offsets();
|
||||||
|
MutableSpan<float3> positions_ = geometry.positions();
|
||||||
|
MutableSpan<bool> cyclic = geometry.cyclic();
|
||||||
|
|
||||||
|
float *curves_weights = nullptr;
|
||||||
|
int *curves_orders = nullptr;
|
||||||
|
|
||||||
|
int *curves_resolution = static_cast<int *>(CustomData_add_layer_named(&geometry.curve_data,
|
||||||
|
CD_PROP_INT32,
|
||||||
|
CD_DEFAULT,
|
||||||
|
nullptr,
|
||||||
|
geometry.curve_size,
|
||||||
|
"resolution"));
|
||||||
|
|
||||||
|
const int resolution = get_curve_resolution(schema, sample_sel);
|
||||||
|
for (int64_t i : geometry.curves_range()) {
|
||||||
|
curves_resolution[i] = resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!geometry.radius) {
|
||||||
|
geometry.radius = static_cast<float *>(CustomData_add_layer_named(
|
||||||
|
&geometry.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, geometry.point_size, "radius"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Knots are not imported anymore. */
|
||||||
|
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
|
||||||
|
const P3fArraySamplePtr positions = smp.getPositions();
|
||||||
|
const FloatArraySamplePtr weights = smp.getPositionWeights();
|
||||||
|
const CurvePeriodicity periodicity = smp.getWrap();
|
||||||
|
const UcharArraySamplePtr orders = smp.getOrders();
|
||||||
|
|
||||||
|
const IFloatGeomParam widths_param = schema.getWidthsParam();
|
||||||
|
FloatArraySamplePtr radiuses;
|
||||||
|
|
||||||
|
if (widths_param.valid()) {
|
||||||
|
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
|
||||||
|
radiuses = wsample.getVals();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
|
||||||
|
float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
|
||||||
|
|
||||||
|
const bool do_weights = (weights != nullptr) && (weights->size() > 1);
|
||||||
|
if (do_weights) {
|
||||||
|
curves_weights = static_cast<float *>(CustomData_add_layer_named(&geometry.point_data,
|
||||||
|
CD_PROP_FLOAT,
|
||||||
|
CD_DEFAULT,
|
||||||
|
nullptr,
|
||||||
|
geometry.point_size,
|
||||||
|
"nurbs_weight"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool do_curves_orders = (orders != nullptr) && (orders->size() > 1);
|
||||||
|
if (do_curves_orders) {
|
||||||
|
curves_orders = static_cast<int *>(CustomData_add_layer_named(&geometry.curve_data,
|
||||||
|
CD_PROP_INT32,
|
||||||
|
CD_DEFAULT,
|
||||||
|
nullptr,
|
||||||
|
geometry.curve_size,
|
||||||
|
"nurbs_order"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
size_t position_offset = 0;
|
||||||
|
for (size_t i = 0; i < num_vertices->size(); i++) {
|
||||||
|
const int num_verts = (*num_vertices)[i];
|
||||||
|
offsets[i] = offset;
|
||||||
|
|
||||||
|
const int curve_order = get_curve_order(smp.getType(), orders, i);
|
||||||
|
if (do_curves_orders) {
|
||||||
|
curves_orders[i] = curve_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the curve is cyclic. */
|
||||||
|
const int overlap = get_curve_overlap(
|
||||||
|
periodicity, positions, position_offset, num_verts, curve_order);
|
||||||
|
|
||||||
|
const bool is_cyclic = overlap != 0;
|
||||||
|
cyclic[i] = is_cyclic;
|
||||||
|
|
||||||
|
for (int j = 0; j < num_verts - overlap; j++, position_offset++) {
|
||||||
|
const Imath::V3f &pos = (*positions)[position_offset];
|
||||||
|
|
||||||
|
copy_zup_from_yup(positions_[position_offset], pos.getValue());
|
||||||
|
|
||||||
|
if (do_radius) {
|
||||||
|
radius = (*radiuses)[position_offset];
|
||||||
|
}
|
||||||
|
geometry.radius[position_offset] = radius;
|
||||||
|
|
||||||
|
if (do_weights) {
|
||||||
|
curves_weights[position_offset] = (*weights)[position_offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += num_verts;
|
||||||
|
/* Skip duplicate positions due to cyclicity. */
|
||||||
|
position_offset += overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
offsets[geometry.curve_size] = offset;
|
||||||
|
|
||||||
|
/* Attributes. */
|
||||||
|
CDStreamConfig config;
|
||||||
|
config.id = &curves->id;
|
||||||
|
config.attr_selector = attribute_selector;
|
||||||
|
config.time = sample_sel.getRequestedTime();
|
||||||
|
config.modifier_error_message = err_str;
|
||||||
|
BKE_id_attribute_get_domains(config.id, config.domain_info);
|
||||||
|
|
||||||
|
read_arbitrary_attributes(config, schema, {}, sample_sel, velocity_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbcCurveReader::read_curves_sample(Curves *curves,
|
||||||
|
const ICurvesSchema &schema,
|
||||||
|
const ISampleSelector &sample_sel)
|
||||||
{
|
{
|
||||||
ICurvesSchema::Sample smp;
|
ICurvesSchema::Sample smp;
|
||||||
try {
|
try {
|
||||||
@@ -120,150 +322,22 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
|
|||||||
|
|
||||||
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
|
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
|
||||||
const P3fArraySamplePtr positions = smp.getPositions();
|
const P3fArraySamplePtr positions = smp.getPositions();
|
||||||
const FloatArraySamplePtr weights = smp.getPositionWeights();
|
|
||||||
const FloatArraySamplePtr knots = smp.getKnots();
|
|
||||||
const CurvePeriodicity periodicity = smp.getWrap();
|
|
||||||
const UcharArraySamplePtr orders = smp.getOrders();
|
|
||||||
|
|
||||||
const IFloatGeomParam widths_param = schema.getWidthsParam();
|
const int point_size = abc_curves_get_total_point_size(num_vertices);
|
||||||
FloatArraySamplePtr radiuses;
|
const int curve_size = static_cast<int>(num_vertices->size());
|
||||||
|
|
||||||
if (widths_param.valid()) {
|
bke::CurvesGeometry &geometry = bke::CurvesGeometry::wrap(curves->geometry);
|
||||||
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
|
geometry.resize(point_size, curve_size);
|
||||||
radiuses = wsample.getVals();
|
|
||||||
}
|
|
||||||
|
|
||||||
int knot_offset = 0;
|
read_curves_sample_ex(curves, m_curves_schema, smp, sample_sel, nullptr, 0.0f, nullptr);
|
||||||
|
|
||||||
size_t idx = 0;
|
|
||||||
for (size_t i = 0; i < num_vertices->size(); i++) {
|
|
||||||
const int num_verts = (*num_vertices)[i];
|
|
||||||
|
|
||||||
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
|
|
||||||
nu->resolu = cu->resolu;
|
|
||||||
nu->resolv = cu->resolv;
|
|
||||||
nu->pntsu = num_verts;
|
|
||||||
nu->pntsv = 1;
|
|
||||||
nu->flag |= CU_SMOOTH;
|
|
||||||
|
|
||||||
switch (smp.getType()) {
|
|
||||||
case Alembic::AbcGeom::kCubic:
|
|
||||||
nu->orderu = 4;
|
|
||||||
break;
|
|
||||||
case Alembic::AbcGeom::kVariableOrder:
|
|
||||||
if (orders && orders->size() > i) {
|
|
||||||
nu->orderu = static_cast<short>((*orders)[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ATTR_FALLTHROUGH;
|
|
||||||
case Alembic::AbcGeom::kLinear:
|
|
||||||
default:
|
|
||||||
nu->orderu = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
|
|
||||||
nu->flagu |= CU_NURB_ENDPOINT;
|
|
||||||
}
|
|
||||||
else if (periodicity == Alembic::AbcGeom::kPeriodic) {
|
|
||||||
nu->flagu |= CU_NURB_CYCLIC;
|
|
||||||
|
|
||||||
/* Check the number of points which overlap, we don't have
|
|
||||||
* overlapping points in Blender, but other software do use them to
|
|
||||||
* indicate that a curve is actually cyclic. Usually the number of
|
|
||||||
* overlapping points is equal to the order/degree of the curve.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const int start = idx;
|
|
||||||
const int end = idx + num_verts;
|
|
||||||
int overlap = 0;
|
|
||||||
|
|
||||||
for (int j = start, k = end - nu->orderu; j < nu->orderu; j++, k++) {
|
|
||||||
const Imath::V3f &p1 = (*positions)[j];
|
|
||||||
const Imath::V3f &p2 = (*positions)[k];
|
|
||||||
|
|
||||||
if (p1 != p2) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
overlap++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Special case, need to figure out how it coincides with knots. */
|
|
||||||
if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
|
|
||||||
overlap = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There is no real cycles. */
|
|
||||||
if (overlap == 0) {
|
|
||||||
nu->flagu &= ~CU_NURB_CYCLIC;
|
|
||||||
nu->flagu |= CU_NURB_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
nu->pntsu -= overlap;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool do_weights = (weights != nullptr) && (weights->size() > 1);
|
|
||||||
float weight = 1.0f;
|
|
||||||
|
|
||||||
const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
|
|
||||||
float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
|
|
||||||
|
|
||||||
nu->type = CU_NURBS;
|
|
||||||
|
|
||||||
nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
|
|
||||||
BPoint *bp = nu->bp;
|
|
||||||
|
|
||||||
for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
|
|
||||||
const Imath::V3f &pos = (*positions)[idx];
|
|
||||||
|
|
||||||
if (do_radius) {
|
|
||||||
radius = (*radiuses)[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (do_weights) {
|
|
||||||
weight = (*weights)[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_zup_from_yup(bp->vec, pos.getValue());
|
|
||||||
bp->vec[3] = weight;
|
|
||||||
bp->f1 = SELECT;
|
|
||||||
bp->radius = radius;
|
|
||||||
bp->weight = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (knots && knots->size() != 0) {
|
|
||||||
nu->knotsu = static_cast<float *>(
|
|
||||||
MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
|
|
||||||
|
|
||||||
/* TODO: second check is temporary, for until the check for cycles is rock solid. */
|
|
||||||
if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
|
|
||||||
/* Skip first and last knots. */
|
|
||||||
for (size_t i = 1; i < knots->size() - 1; i++) {
|
|
||||||
nu->knotsu[i - 1] = (*knots)[knot_offset + i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* TODO: figure out how to use the knots array from other
|
|
||||||
* software in this case. */
|
|
||||||
BKE_nurb_knot_calc_u(nu);
|
|
||||||
}
|
|
||||||
|
|
||||||
knot_offset += knots->size();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BKE_nurb_knot_calc_u(nu);
|
|
||||||
}
|
|
||||||
|
|
||||||
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
|
void AbcCurveReader::read_geometry(GeometrySet &geometry_set,
|
||||||
const ISampleSelector &sample_sel,
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
int /*read_flag*/,
|
const AttributeSelector *attribute_selector,
|
||||||
const char * /*velocity_name*/,
|
int /*read_flag*/,
|
||||||
const float /*velocity_scale*/,
|
const float velocity_scale,
|
||||||
const char **err_str)
|
const char **err_str)
|
||||||
{
|
{
|
||||||
ICurvesSchema::Sample sample;
|
ICurvesSchema::Sample sample;
|
||||||
|
|
||||||
@@ -277,61 +351,22 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
|
|||||||
m_curves_schema.getName().c_str(),
|
m_curves_schema.getName().c_str(),
|
||||||
sample_sel.getRequestedTime(),
|
sample_sel.getRequestedTime(),
|
||||||
ex.what());
|
ex.what());
|
||||||
return existing_mesh;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const P3fArraySamplePtr &positions = sample.getPositions();
|
|
||||||
const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
|
const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
|
||||||
|
const P3fArraySamplePtr positions = sample.getPositions();
|
||||||
|
|
||||||
int vertex_idx = 0;
|
Curves *curves = geometry_set.get_curves_for_write();
|
||||||
int curve_idx;
|
|
||||||
Curve *curve = static_cast<Curve *>(m_object->data);
|
|
||||||
|
|
||||||
const int curve_count = BLI_listbase_count(&curve->nurb);
|
const int point_size = abc_curves_get_total_point_size(num_vertices);
|
||||||
bool same_topology = curve_count == num_vertices->size();
|
const int curve_size = static_cast<int>(num_vertices->size());
|
||||||
|
|
||||||
if (same_topology) {
|
bke::CurvesGeometry &geometry = bke::CurvesGeometry::wrap(curves->geometry);
|
||||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
geometry.resize(point_size, curve_size);
|
||||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
|
||||||
const int num_in_alembic = (*num_vertices)[curve_idx];
|
|
||||||
const int num_in_blender = nurbs->pntsu;
|
|
||||||
|
|
||||||
if (num_in_alembic != num_in_blender) {
|
read_curves_sample_ex(
|
||||||
same_topology = false;
|
curves, m_curves_schema, sample, sample_sel, attribute_selector, velocity_scale, err_str);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!same_topology) {
|
|
||||||
BKE_nurbList_free(&curve->nurb);
|
|
||||||
read_curve_sample(curve, m_curves_schema, sample_sel);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
|
||||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
|
||||||
const int totpoint = (*num_vertices)[curve_idx];
|
|
||||||
|
|
||||||
if (nurbs->bp) {
|
|
||||||
BPoint *point = nurbs->bp;
|
|
||||||
|
|
||||||
for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
|
|
||||||
const Imath::V3f &pos = (*positions)[vertex_idx];
|
|
||||||
copy_zup_from_yup(point->vec, pos.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (nurbs->bezt) {
|
|
||||||
BezTriple *bezier = nurbs->bezt;
|
|
||||||
|
|
||||||
for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
|
|
||||||
const Imath::V3f &pos = (*positions)[vertex_idx];
|
|
||||||
copy_zup_from_yup(bezier->vec[1], pos.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return BKE_mesh_new_nomain_from_curve(m_object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
#include "abc_reader_mesh.h"
|
#include "abc_reader_mesh.h"
|
||||||
#include "abc_reader_object.h"
|
#include "abc_reader_object.h"
|
||||||
|
|
||||||
struct Curve;
|
struct Curves;
|
||||||
|
|
||||||
#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution"
|
#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution"
|
||||||
|
|
||||||
@@ -26,7 +26,10 @@ class AbcCurveReader final : public AbcObjectReader {
|
|||||||
const Object *const ob,
|
const Object *const ob,
|
||||||
const char **err_str) const override;
|
const char **err_str) const override;
|
||||||
|
|
||||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \note Alembic only stores data about control points, but the Mesh
|
* \note Alembic only stores data about control points, but the Mesh
|
||||||
* passed from the cache modifier contains the #DispList, which has more data
|
* passed from the cache modifier contains the #DispList, which has more data
|
||||||
@@ -34,16 +37,16 @@ class AbcCurveReader final : public AbcObjectReader {
|
|||||||
* object directly and create a new Mesh from that. Also we might need to
|
* object directly and create a new Mesh from that. Also we might need to
|
||||||
* create new or delete existing NURBS in the curve.
|
* create new or delete existing NURBS in the curve.
|
||||||
*/
|
*/
|
||||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
void read_geometry(GeometrySet &geometry_set,
|
||||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
int read_flag,
|
const AttributeSelector *attribute_selector,
|
||||||
const char *velocity_name,
|
int read_flag,
|
||||||
float velocity_scale,
|
const float velocity_scale,
|
||||||
const char **err_str) override;
|
const char **err_str) override;
|
||||||
|
|
||||||
void read_curve_sample(Curve *cu,
|
void read_curves_sample(Curves *curves,
|
||||||
const Alembic::AbcGeom::ICurvesSchema &schema,
|
const Alembic::AbcGeom::ICurvesSchema &schema,
|
||||||
const Alembic::Abc::ISampleSelector &sample_selector);
|
const Alembic::Abc::ISampleSelector &sample_selector);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
60
source/blender/io/alembic/intern/abc_reader_instance.cc
Normal file
60
source/blender/io/alembic/intern/abc_reader_instance.cc
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include "abc_reader_instance.h"
|
||||||
|
|
||||||
|
#include "DNA_object_types.h"
|
||||||
|
|
||||||
|
#include "BLI_assert.h"
|
||||||
|
|
||||||
|
#include "BKE_lib_id.h"
|
||||||
|
#include "BKE_lib_remap.h"
|
||||||
|
#include "BKE_object.h"
|
||||||
|
|
||||||
|
#include "abc_reader_manager.h"
|
||||||
|
|
||||||
|
namespace blender::io::alembic {
|
||||||
|
|
||||||
|
AbcInstanceReader::AbcInstanceReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||||
|
: AbcObjectReader(object, settings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbcInstanceReader::valid() const
|
||||||
|
{
|
||||||
|
// TODO(kevindietrich)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbcInstanceReader::accepts_object_type(
|
||||||
|
const Alembic::AbcCoreAbstract::ObjectHeader & /*alembic_header*/,
|
||||||
|
const Object *const /*ob*/,
|
||||||
|
const char ** /*err_str*/) const
|
||||||
|
{
|
||||||
|
/* TODO(kevindietrich) */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbcInstanceReader::readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector & /* sample_sel */)
|
||||||
|
{
|
||||||
|
/* For reference on duplication, see ED_object_add_duplicate_linked.
|
||||||
|
*
|
||||||
|
* In this function, we only duplicate the object, as the rest (adding to view layer, tagging the
|
||||||
|
* depsgraph, etc.) is done at the end of the import.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Object *ob = manager.get_blender_object_for_path(m_iobject.instanceSourcePath());
|
||||||
|
BLI_assert(ob);
|
||||||
|
/* 0 = linked */
|
||||||
|
uint dupflag = 0;
|
||||||
|
uint duplicate_options = LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID;
|
||||||
|
|
||||||
|
m_object = static_cast<Object *>(
|
||||||
|
ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)));
|
||||||
|
|
||||||
|
/* link own references to the newly duplicated data T26816. */
|
||||||
|
BKE_libblock_relink_to_newid(bmain, &m_object->id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender::io::alembic
|
28
source/blender/io/alembic/intern/abc_reader_instance.h
Normal file
28
source/blender/io/alembic/intern/abc_reader_instance.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup balembic
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "abc_reader_object.h"
|
||||||
|
|
||||||
|
namespace blender::io::alembic {
|
||||||
|
|
||||||
|
class AbcInstanceReader final : public AbcObjectReader {
|
||||||
|
public:
|
||||||
|
AbcInstanceReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||||
|
|
||||||
|
bool valid() const override;
|
||||||
|
|
||||||
|
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
||||||
|
const Object *const ob,
|
||||||
|
const char **err_str) const override;
|
||||||
|
|
||||||
|
void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace blender::io::alembic
|
41
source/blender/io/alembic/intern/abc_reader_manager.cc
Normal file
41
source/blender/io/alembic/intern/abc_reader_manager.cc
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup balembic
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "abc_reader_manager.h"
|
||||||
|
|
||||||
|
#include "abc_reader_instance.h"
|
||||||
|
|
||||||
|
namespace blender::io::alembic {
|
||||||
|
|
||||||
|
AbcObjectReader *AbcReaderManager::create_instance_reader(Alembic::Abc::v12::IObject iobject,
|
||||||
|
ImportSettings &settings)
|
||||||
|
{
|
||||||
|
std::cerr << "Creating an instance reader...\n";
|
||||||
|
AbcObjectReader *reader = new AbcInstanceReader(iobject, settings);
|
||||||
|
m_instance_readers.push_back(reader);
|
||||||
|
m_readers_all.push_back(reader);
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *AbcReaderManager::get_blender_object_for_path(const std::string &path) const
|
||||||
|
{
|
||||||
|
AbcObjectReader *reader = get_object_reader_for_path(path);
|
||||||
|
if (!reader) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return reader->object();
|
||||||
|
}
|
||||||
|
|
||||||
|
AbcObjectReader *AbcReaderManager::get_object_reader_for_path(const std::string &path) const
|
||||||
|
{
|
||||||
|
MapIteratorType iter = m_readers_map.find(path);
|
||||||
|
if (iter == m_readers_map.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender::io::alembic
|
64
source/blender/io/alembic/intern/abc_reader_manager.h
Normal file
64
source/blender/io/alembic/intern/abc_reader_manager.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup balembic
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "abc_reader_object.h"
|
||||||
|
|
||||||
|
namespace blender::io::alembic {
|
||||||
|
|
||||||
|
class AbcReaderManager {
|
||||||
|
using MapType = std::map<std::string, AbcObjectReader *>;
|
||||||
|
using MapIteratorType = MapType::const_iterator;
|
||||||
|
std::map<std::string, AbcObjectReader *> m_readers_map{};
|
||||||
|
|
||||||
|
AbcObjectReader::ptr_vector m_readers;
|
||||||
|
AbcObjectReader::ptr_vector m_readers_all;
|
||||||
|
AbcObjectReader::ptr_vector m_instance_readers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename ReaderType>
|
||||||
|
AbcObjectReader *create(Alembic::Abc::IObject iobject, ImportSettings &settings)
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of_v<AbcObjectReader, ReaderType>,
|
||||||
|
"Trying to create a reader from a class which does not derive from AbcObjectReader !");
|
||||||
|
|
||||||
|
if (iobject.isInstanceRoot()) {
|
||||||
|
return create_instance_reader(iobject, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReaderType *reader = new ReaderType(iobject, settings);
|
||||||
|
m_readers_map[iobject.getFullName()] = reader;
|
||||||
|
m_readers.push_back(reader);
|
||||||
|
m_readers_all.push_back(reader);
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbcObjectReader *create_instance_reader(Alembic::Abc::IObject iobject, ImportSettings &settings);
|
||||||
|
|
||||||
|
Object *get_blender_object_for_path(const std::string &path) const;
|
||||||
|
|
||||||
|
const AbcObjectReader::ptr_vector &all_readers() const
|
||||||
|
{
|
||||||
|
return m_readers_all;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AbcObjectReader::ptr_vector &instance_readers() const
|
||||||
|
{
|
||||||
|
return m_instance_readers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AbcObjectReader::ptr_vector &data_readers() const
|
||||||
|
{
|
||||||
|
return m_readers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AbcObjectReader *get_object_reader_for_path(const std::string &path) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace blender::io::alembic
|
@@ -24,7 +24,7 @@
|
|||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_math_geom.h"
|
#include "BLI_math_geom.h"
|
||||||
|
|
||||||
#include "BKE_attribute.h"
|
#include "BKE_geometry_set.hh"
|
||||||
#include "BKE_main.h"
|
#include "BKE_main.h"
|
||||||
#include "BKE_material.h"
|
#include "BKE_material.h"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
@@ -112,10 +112,6 @@ struct AbcMeshData {
|
|||||||
|
|
||||||
P3fArraySamplePtr positions;
|
P3fArraySamplePtr positions;
|
||||||
P3fArraySamplePtr ceil_positions;
|
P3fArraySamplePtr ceil_positions;
|
||||||
|
|
||||||
AbcUvScope uv_scope;
|
|
||||||
V2fArraySamplePtr uvs;
|
|
||||||
UInt32ArraySamplePtr uvs_indices;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void read_mverts_interp(MVert *mverts,
|
static void read_mverts_interp(MVert *mverts,
|
||||||
@@ -175,21 +171,12 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
|||||||
{
|
{
|
||||||
MPoly *mpolys = config.mpoly;
|
MPoly *mpolys = config.mpoly;
|
||||||
MLoop *mloops = config.mloop;
|
MLoop *mloops = config.mloop;
|
||||||
MLoopUV *mloopuvs = config.mloopuv;
|
|
||||||
|
|
||||||
const Int32ArraySamplePtr &face_indices = mesh_data.face_indices;
|
const Int32ArraySamplePtr &face_indices = mesh_data.face_indices;
|
||||||
const Int32ArraySamplePtr &face_counts = mesh_data.face_counts;
|
const Int32ArraySamplePtr &face_counts = mesh_data.face_counts;
|
||||||
const V2fArraySamplePtr &uvs = mesh_data.uvs;
|
|
||||||
const size_t uvs_size = uvs == nullptr ? 0 : uvs->size();
|
|
||||||
|
|
||||||
const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
|
|
||||||
|
|
||||||
const bool do_uvs = (mloopuvs && uvs && uvs_indices);
|
|
||||||
const bool do_uvs_per_loop = do_uvs && mesh_data.uv_scope == ABC_UV_SCOPE_LOOP;
|
|
||||||
BLI_assert(!do_uvs || mesh_data.uv_scope != ABC_UV_SCOPE_NONE);
|
|
||||||
unsigned int loop_index = 0;
|
unsigned int loop_index = 0;
|
||||||
unsigned int rev_loop_index = 0;
|
unsigned int rev_loop_index = 0;
|
||||||
unsigned int uv_index = 0;
|
|
||||||
bool seen_invalid_geometry = false;
|
bool seen_invalid_geometry = false;
|
||||||
|
|
||||||
for (int i = 0; i < face_counts->size(); i++) {
|
for (int i = 0; i < face_counts->size(); i++) {
|
||||||
@@ -217,19 +204,6 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
|||||||
seen_invalid_geometry = true;
|
seen_invalid_geometry = true;
|
||||||
}
|
}
|
||||||
last_vertex_index = loop.v;
|
last_vertex_index = loop.v;
|
||||||
|
|
||||||
if (do_uvs) {
|
|
||||||
MLoopUV &loopuv = mloopuvs[rev_loop_index];
|
|
||||||
uv_index = (*uvs_indices)[do_uvs_per_loop ? loop_index : loop.v];
|
|
||||||
|
|
||||||
/* Some Alembic files are broken (or at least export UVs in a way we don't expect). */
|
|
||||||
if (uv_index >= uvs_size) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
loopuv.uv[0] = (*uvs)[uv_index][0];
|
|
||||||
loopuv.uv[1] = (*uvs)[uv_index][1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,68 +311,6 @@ static void process_normals(CDStreamConfig &config,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BLI_INLINE void read_uvs_params(CDStreamConfig &config,
|
|
||||||
AbcMeshData &abc_data,
|
|
||||||
const IV2fGeomParam &uv,
|
|
||||||
const ISampleSelector &selector)
|
|
||||||
{
|
|
||||||
if (!uv.valid()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IV2fGeomParam::Sample uvsamp;
|
|
||||||
uv.getIndexed(uvsamp, selector);
|
|
||||||
|
|
||||||
UInt32ArraySamplePtr uvs_indices = uvsamp.getIndices();
|
|
||||||
|
|
||||||
const AbcUvScope uv_scope = get_uv_scope(uv.getScope(), config, uvs_indices);
|
|
||||||
|
|
||||||
if (uv_scope == ABC_UV_SCOPE_NONE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
abc_data.uv_scope = uv_scope;
|
|
||||||
abc_data.uvs = uvsamp.getVals();
|
|
||||||
abc_data.uvs_indices = uvs_indices;
|
|
||||||
|
|
||||||
std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
|
|
||||||
|
|
||||||
/* According to the convention, primary UVs should have had their name
|
|
||||||
* set using Alembic::Abc::SetSourceName, but you can't expect everyone
|
|
||||||
* to follow it! :) */
|
|
||||||
if (name.empty()) {
|
|
||||||
name = uv.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
void *cd_ptr = config.add_customdata_cb(config.mesh, name.c_str(), CD_MLOOPUV);
|
|
||||||
config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
loopdata = &mesh->ldata;
|
|
||||||
cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
|
|
||||||
if (cd_ptr != nullptr) {
|
|
||||||
/* 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, nullptr, numloops, name);
|
|
||||||
return cd_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_weight_and_index(CDStreamConfig &config,
|
static void get_weight_and_index(CDStreamConfig &config,
|
||||||
Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
|
Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
|
||||||
size_t samples_number)
|
size_t samples_number)
|
||||||
@@ -411,65 +323,7 @@ static void get_weight_and_index(CDStreamConfig &config,
|
|||||||
config.ceil_index = i1;
|
config.ceil_index = i1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema,
|
static void read_mesh_sample(ImportSettings *settings,
|
||||||
const ISampleSelector &selector,
|
|
||||||
const std::string &name)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < schema.getNumProperties(); i++) {
|
|
||||||
const PropertyHeader &header = schema.getPropertyHeader(i);
|
|
||||||
|
|
||||||
if (header.isCompound()) {
|
|
||||||
const ICompoundProperty &prop = ICompoundProperty(schema, header.getName());
|
|
||||||
|
|
||||||
if (has_property(prop, name)) {
|
|
||||||
/* Header cannot be null here, as its presence is checked via has_property, so it is safe
|
|
||||||
* to dereference. */
|
|
||||||
const PropertyHeader *header = prop.getPropertyHeader(name);
|
|
||||||
if (!IV3fArrayProperty::matches(*header)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
|
|
||||||
if (velocity_prop) {
|
|
||||||
return velocity_prop.getValue(selector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (header.isArray()) {
|
|
||||||
if (header.getName() == name && IV3fArrayProperty::matches(header)) {
|
|
||||||
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
|
|
||||||
return velocity_prop.getValue(selector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return V3fArraySamplePtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_velocity(const V3fArraySamplePtr &velocities,
|
|
||||||
const CDStreamConfig &config,
|
|
||||||
const float velocity_scale)
|
|
||||||
{
|
|
||||||
const int num_velocity_vectors = static_cast<int>(velocities->size());
|
|
||||||
if (num_velocity_vectors != config.mesh->totvert) {
|
|
||||||
/* Files containing videogrammetry data may be malformed and export velocity data on missing
|
|
||||||
* frames (most likely by copying the last valid data). */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomDataLayer *velocity_layer = BKE_id_attribute_new(
|
|
||||||
&config.mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, nullptr);
|
|
||||||
float(*velocity)[3] = (float(*)[3])velocity_layer->data;
|
|
||||||
|
|
||||||
for (int i = 0; i < num_velocity_vectors; i++) {
|
|
||||||
const Imath::V3f &vel_in = (*velocities)[i];
|
|
||||||
copy_zup_from_yup(velocity[i], vel_in.getValue());
|
|
||||||
mul_v3_fl(velocity[i], velocity_scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_mesh_sample(const std::string &iobject_full_name,
|
|
||||||
ImportSettings *settings,
|
|
||||||
const IPolyMeshSchema &schema,
|
const IPolyMeshSchema &schema,
|
||||||
const ISampleSelector &selector,
|
const ISampleSelector &selector,
|
||||||
CDStreamConfig &config)
|
CDStreamConfig &config)
|
||||||
@@ -489,13 +343,8 @@ static void read_mesh_sample(const std::string &iobject_full_name,
|
|||||||
abc_mesh_data.ceil_positions = ceil_sample.getPositions();
|
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) {
|
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
|
||||||
read_mverts(config, abc_mesh_data);
|
read_mverts(config, abc_mesh_data);
|
||||||
read_generated_coordinates(schema.getArbGeomParams(), config, selector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
|
if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
|
||||||
@@ -503,25 +352,21 @@ static void read_mesh_sample(const std::string &iobject_full_name,
|
|||||||
process_normals(config, schema.getNormalsParam(), selector);
|
process_normals(config, schema.getNormalsParam(), selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
|
read_arbitrary_attributes(
|
||||||
read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector);
|
config, schema, schema.getUVsParam(), selector, settings->velocity_scale);
|
||||||
}
|
|
||||||
|
|
||||||
if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
|
|
||||||
V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
|
|
||||||
if (velocities) {
|
|
||||||
read_velocity(velocities, config, settings->velocity_scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
|
CDStreamConfig get_config(Mesh *mesh,
|
||||||
|
const AttributeSelector *attr_selector,
|
||||||
|
const std::string &iobject_full_name,
|
||||||
|
const bool use_vertex_interpolation)
|
||||||
{
|
{
|
||||||
CDStreamConfig config;
|
CDStreamConfig config;
|
||||||
|
|
||||||
BLI_assert(mesh->mvert || mesh->totvert == 0);
|
BLI_assert(mesh->mvert || mesh->totvert == 0);
|
||||||
|
|
||||||
config.mesh = mesh;
|
config.mesh = mesh;
|
||||||
|
config.id = &mesh->id;
|
||||||
config.mvert = mesh->mvert;
|
config.mvert = mesh->mvert;
|
||||||
config.mloop = mesh->mloop;
|
config.mloop = mesh->mloop;
|
||||||
config.mpoly = mesh->mpoly;
|
config.mpoly = mesh->mpoly;
|
||||||
@@ -529,8 +374,10 @@ CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
|
|||||||
config.totloop = mesh->totloop;
|
config.totloop = mesh->totloop;
|
||||||
config.totpoly = mesh->totpoly;
|
config.totpoly = mesh->totpoly;
|
||||||
config.loopdata = &mesh->ldata;
|
config.loopdata = &mesh->ldata;
|
||||||
config.add_customdata_cb = add_customdata_cb;
|
|
||||||
config.use_vertex_interpolation = use_vertex_interpolation;
|
config.use_vertex_interpolation = use_vertex_interpolation;
|
||||||
|
config.attr_selector = attr_selector;
|
||||||
|
config.iobject_full_name = iobject_full_name;
|
||||||
|
BKE_id_attribute_get_domains(config.id, config.domain_info);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@@ -553,39 +400,6 @@ bool AbcMeshReader::valid() const
|
|||||||
return m_schema.valid();
|
return m_schema.valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class typedGeomParam>
|
|
||||||
bool is_valid_animated(const ICompoundProperty arbGeomParams, const PropertyHeader &prop_header)
|
|
||||||
{
|
|
||||||
if (!typedGeomParam::matches(prop_header)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedGeomParam geom_param(arbGeomParams, prop_header.getName());
|
|
||||||
return geom_param.valid() && !geom_param.isConstant();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool has_animated_geom_params(const ICompoundProperty arbGeomParams)
|
|
||||||
{
|
|
||||||
if (!arbGeomParams.valid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int num_props = arbGeomParams.getNumProperties();
|
|
||||||
for (int i = 0; i < num_props; i++) {
|
|
||||||
const PropertyHeader &prop_header = arbGeomParams.getPropertyHeader(i);
|
|
||||||
|
|
||||||
/* These are interpreted as vertex colors later (see 'read_custom_data'). */
|
|
||||||
if (is_valid_animated<IC3fGeomParam>(arbGeomParams, prop_header)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (is_valid_animated<IC4fGeomParam>(arbGeomParams, prop_header)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Specialization of #has_animations() as defined in abc_reader_object.h. */
|
/* Specialization of #has_animations() as defined in abc_reader_object.h. */
|
||||||
template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
|
template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
|
||||||
{
|
{
|
||||||
@@ -604,21 +418,30 @@ template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, Import
|
|||||||
}
|
}
|
||||||
|
|
||||||
ICompoundProperty arbGeomParams = schema.getArbGeomParams();
|
ICompoundProperty arbGeomParams = schema.getArbGeomParams();
|
||||||
if (has_animated_geom_params(arbGeomParams)) {
|
if (has_animated_attributes(arbGeomParams)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
void AbcMeshReader::readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager & /*manager*/,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||||
{
|
{
|
||||||
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
||||||
|
|
||||||
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
||||||
m_object->data = mesh;
|
m_object->data = mesh;
|
||||||
|
|
||||||
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
|
/* Default AttributeSelector to ensure that at least UVs and vertex colors are read. To load
|
||||||
|
* other attributes, a modifier should be added as there are no clear conventions for them. */
|
||||||
|
ListBase lb = {nullptr, nullptr};
|
||||||
|
AttributeSelector attr_selector(&lb);
|
||||||
|
attr_selector.set_read_flags(MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR);
|
||||||
|
|
||||||
|
Mesh *read_mesh = this->read_mesh(
|
||||||
|
mesh, sample_sel, &attr_selector, MOD_MESHSEQ_READ_ALL, 0.0f, nullptr);
|
||||||
if (read_mesh != mesh) {
|
if (read_mesh != mesh) {
|
||||||
/* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_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. */
|
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
|
||||||
@@ -683,10 +506,31 @@ bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector
|
|||||||
face_indices->size() != existing_mesh->totloop;
|
face_indices->size() != existing_mesh->totloop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbcMeshReader::read_geometry(GeometrySet &geometry_set,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
|
int read_flag,
|
||||||
|
const float velocity_scale,
|
||||||
|
const char **err_str)
|
||||||
|
{
|
||||||
|
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||||
|
|
||||||
|
if (mesh == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh *new_mesh = read_mesh(
|
||||||
|
mesh, sample_sel, attribute_selector, read_flag, velocity_scale, err_str);
|
||||||
|
|
||||||
|
if (new_mesh != mesh) {
|
||||||
|
geometry_set.replace_mesh(new_mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
|
Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
|
||||||
const ISampleSelector &sample_sel,
|
const ISampleSelector &sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
const int read_flag,
|
const int read_flag,
|
||||||
const char *velocity_name,
|
|
||||||
const float velocity_scale,
|
const float velocity_scale,
|
||||||
const char **err_str)
|
const char **err_str)
|
||||||
{
|
{
|
||||||
@@ -730,7 +574,6 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
|
|||||||
/* Only read point data when streaming meshes, unless we need to create new ones. */
|
/* Only read point data when streaming meshes, unless we need to create new ones. */
|
||||||
ImportSettings settings;
|
ImportSettings settings;
|
||||||
settings.read_flag |= read_flag;
|
settings.read_flag |= read_flag;
|
||||||
settings.velocity_name = velocity_name;
|
|
||||||
settings.velocity_scale = velocity_scale;
|
settings.velocity_scale = velocity_scale;
|
||||||
|
|
||||||
if (topology_changed(existing_mesh, sample_sel)) {
|
if (topology_changed(existing_mesh, sample_sel)) {
|
||||||
@@ -757,11 +600,12 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
|
|||||||
|
|
||||||
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
|
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
|
||||||
const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
|
const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
|
||||||
CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
|
CDStreamConfig config = get_config(
|
||||||
|
mesh_to_export, attribute_selector, m_iobject.getFullName(), use_vertex_interpolation);
|
||||||
config.time = sample_sel.getRequestedTime();
|
config.time = sample_sel.getRequestedTime();
|
||||||
config.modifier_error_message = err_str;
|
config.modifier_error_message = err_str;
|
||||||
|
|
||||||
read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
|
read_mesh_sample(&settings, m_schema, sample_sel, config);
|
||||||
|
|
||||||
if (new_mesh) {
|
if (new_mesh) {
|
||||||
/* Here we assume that the number of materials doesn't change, i.e. that
|
/* Here we assume that the number of materials doesn't change, i.e. that
|
||||||
@@ -848,8 +692,7 @@ BLI_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_subd_sample(const std::string &iobject_full_name,
|
static void read_subd_sample(ImportSettings *settings,
|
||||||
ImportSettings *settings,
|
|
||||||
const ISubDSchema &schema,
|
const ISubDSchema &schema,
|
||||||
const ISampleSelector &selector,
|
const ISampleSelector &selector,
|
||||||
CDStreamConfig &config)
|
CDStreamConfig &config)
|
||||||
@@ -869,10 +712,6 @@ static void read_subd_sample(const std::string &iobject_full_name,
|
|||||||
abc_mesh_data.ceil_positions = ceil_sample.getPositions();
|
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) {
|
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
|
||||||
read_mverts(config, abc_mesh_data);
|
read_mverts(config, abc_mesh_data);
|
||||||
}
|
}
|
||||||
@@ -885,16 +724,8 @@ static void read_subd_sample(const std::string &iobject_full_name,
|
|||||||
process_no_normals(config);
|
process_no_normals(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
|
read_arbitrary_attributes(
|
||||||
read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector);
|
config, schema, schema.getUVsParam(), selector, settings->velocity_scale);
|
||||||
}
|
|
||||||
|
|
||||||
if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
|
|
||||||
V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
|
|
||||||
if (velocities) {
|
|
||||||
read_velocity(velocities, config, settings->velocity_scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_vertex_creases(Mesh *mesh,
|
static void read_vertex_creases(Mesh *mesh,
|
||||||
@@ -995,14 +826,23 @@ bool AbcSubDReader::accepts_object_type(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
void AbcSubDReader::readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager & /*manager*/,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||||
{
|
{
|
||||||
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
||||||
|
|
||||||
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
||||||
m_object->data = mesh;
|
m_object->data = mesh;
|
||||||
|
|
||||||
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
|
/* Default AttributeSelector to ensure that at least UVs and vertex colors are read. To load
|
||||||
|
* other attributes, a modifier should be added as there are no clear conventions for them. */
|
||||||
|
ListBase lb = {nullptr, nullptr};
|
||||||
|
AttributeSelector attr_selector(&lb);
|
||||||
|
attr_selector.set_read_flags(MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR);
|
||||||
|
|
||||||
|
Mesh *read_mesh = this->read_mesh(
|
||||||
|
mesh, sample_sel, &attr_selector, MOD_MESHSEQ_READ_ALL, 0.0f, nullptr);
|
||||||
if (read_mesh != mesh) {
|
if (read_mesh != mesh) {
|
||||||
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
|
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
|
||||||
}
|
}
|
||||||
@@ -1035,8 +875,8 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
|
|||||||
|
|
||||||
Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
|
Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
|
||||||
const ISampleSelector &sample_sel,
|
const ISampleSelector &sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
const int read_flag,
|
const int read_flag,
|
||||||
const char *velocity_name,
|
|
||||||
const float velocity_scale,
|
const float velocity_scale,
|
||||||
const char **err_str)
|
const char **err_str)
|
||||||
{
|
{
|
||||||
@@ -1064,7 +904,6 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
|
|||||||
|
|
||||||
ImportSettings settings;
|
ImportSettings settings;
|
||||||
settings.read_flag |= read_flag;
|
settings.read_flag |= read_flag;
|
||||||
settings.velocity_name = velocity_name;
|
|
||||||
settings.velocity_scale = velocity_scale;
|
settings.velocity_scale = velocity_scale;
|
||||||
|
|
||||||
if (existing_mesh->totvert != positions->size()) {
|
if (existing_mesh->totvert != positions->size()) {
|
||||||
@@ -1092,11 +931,33 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
|
|||||||
/* Only read point data when streaming meshes, unless we need to create new ones. */
|
/* Only read point data when streaming meshes, unless we need to create new ones. */
|
||||||
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
|
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
|
||||||
const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
|
const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
|
||||||
CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
|
CDStreamConfig config = get_config(
|
||||||
|
mesh_to_export, attribute_selector, m_iobject.getFullName(), use_vertex_interpolation);
|
||||||
config.time = sample_sel.getRequestedTime();
|
config.time = sample_sel.getRequestedTime();
|
||||||
read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
|
read_subd_sample(&settings, m_schema, sample_sel, config);
|
||||||
|
|
||||||
return mesh_to_export;
|
return mesh_to_export;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbcSubDReader::read_geometry(GeometrySet &geometry_set,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
|
int read_flag,
|
||||||
|
const float velocity_scale,
|
||||||
|
const char **err_str)
|
||||||
|
{
|
||||||
|
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||||
|
|
||||||
|
if (mesh == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh *new_mesh = read_mesh(
|
||||||
|
mesh, sample_sel, attribute_selector, read_flag, velocity_scale, err_str);
|
||||||
|
|
||||||
|
if (new_mesh != mesh) {
|
||||||
|
geometry_set.replace_mesh(new_mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
@@ -24,17 +24,20 @@ class AbcMeshReader final : public AbcObjectReader {
|
|||||||
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
||||||
const Object *const ob,
|
const Object *const ob,
|
||||||
const char **err_str) const override;
|
const char **err_str) const override;
|
||||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
|
|
||||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
|
||||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
|
||||||
int read_flag,
|
|
||||||
const char *velocity_name,
|
|
||||||
float velocity_scale,
|
|
||||||
const char **err_str) override;
|
|
||||||
bool topology_changed(Mesh *existing_mesh,
|
bool topology_changed(Mesh *existing_mesh,
|
||||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
|
|
||||||
|
void read_geometry(GeometrySet &geometry_set,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
|
int read_flag,
|
||||||
|
const float velocity_scale,
|
||||||
|
const char **err_str) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void readFaceSetsSample(Main *bmain,
|
void readFaceSetsSample(Main *bmain,
|
||||||
Mesh *mesh,
|
Mesh *mesh,
|
||||||
@@ -44,6 +47,13 @@ class AbcMeshReader final : public AbcObjectReader {
|
|||||||
MPoly *mpoly,
|
MPoly *mpoly,
|
||||||
int totpoly,
|
int totpoly,
|
||||||
std::map<std::string, int> &r_mat_map);
|
std::map<std::string, int> &r_mat_map);
|
||||||
|
|
||||||
|
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
|
const int read_flag,
|
||||||
|
const float velocity_scale,
|
||||||
|
const char **err_str);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AbcSubDReader final : public AbcObjectReader {
|
class AbcSubDReader final : public AbcObjectReader {
|
||||||
@@ -58,19 +68,33 @@ class AbcSubDReader final : public AbcObjectReader {
|
|||||||
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
||||||
const Object *const ob,
|
const Object *const ob,
|
||||||
const char **err_str) const override;
|
const char **err_str) const override;
|
||||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
|
|
||||||
|
void read_geometry(GeometrySet &geometry_set,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
|
int read_flag,
|
||||||
|
const float velocity_scale,
|
||||||
|
const char **err_str) override;
|
||||||
|
|
||||||
|
private:
|
||||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
int read_flag,
|
const AttributeSelector *attribute_selector,
|
||||||
const char *velocity_name,
|
const int read_flag,
|
||||||
float velocity_scale,
|
const float velocity_scale,
|
||||||
const char **err_str) override;
|
const char **err_str);
|
||||||
};
|
};
|
||||||
|
|
||||||
void read_mverts(Mesh &mesh,
|
void read_mverts(Mesh &mesh,
|
||||||
const Alembic::AbcGeom::P3fArraySamplePtr positions,
|
const Alembic::AbcGeom::P3fArraySamplePtr positions,
|
||||||
const Alembic::AbcGeom::N3fArraySamplePtr normals);
|
const Alembic::AbcGeom::N3fArraySamplePtr normals);
|
||||||
|
|
||||||
CDStreamConfig get_config(struct Mesh *mesh, bool use_vertex_interpolation);
|
CDStreamConfig get_config(struct Mesh *mesh,
|
||||||
|
const AttributeSelector *attr_selector,
|
||||||
|
const std::string &iobject_full_name,
|
||||||
|
bool use_vertex_interpolation);
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
@@ -94,7 +94,9 @@ static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
void AbcNurbsReader::readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager & /*manager*/,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||||
{
|
{
|
||||||
Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, m_data_name.c_str(), OB_SURF));
|
Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, m_data_name.c_str(), OB_SURF));
|
||||||
cu->actvert = CU_ACT_NONE;
|
cu->actvert = CU_ACT_NONE;
|
||||||
|
@@ -21,7 +21,9 @@ class AbcNurbsReader final : public AbcObjectReader {
|
|||||||
const Object *const ob,
|
const Object *const ob,
|
||||||
const char **err_str) const override;
|
const char **err_str) const override;
|
||||||
|
|
||||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void getNurbsPatches(const Alembic::Abc::IObject &obj);
|
void getNurbsPatches(const Alembic::Abc::IObject &obj);
|
||||||
|
@@ -130,16 +130,6 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time)
|
|||||||
return s0.getMatrix();
|
return s0.getMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
|
|
||||||
const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
|
|
||||||
int UNUSED(read_flag),
|
|
||||||
const char *UNUSED(velocity_name),
|
|
||||||
const float UNUSED(velocity_scale),
|
|
||||||
const char **UNUSED(err_str))
|
|
||||||
{
|
|
||||||
return existing_mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
|
bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
|
||||||
const Alembic::Abc::ISampleSelector & /*sample_sel*/)
|
const Alembic::Abc::ISampleSelector & /*sample_sel*/)
|
||||||
{
|
{
|
||||||
@@ -148,6 +138,16 @@ bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbcObjectReader::read_geometry(GeometrySet &UNUSED(geometry_set),
|
||||||
|
const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
|
||||||
|
const AttributeSelector *UNUSED(attribute_selector),
|
||||||
|
int UNUSED(read_flag),
|
||||||
|
const float UNUSED(velocity_scale),
|
||||||
|
const char **UNUSED(err_str))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void AbcObjectReader::setupObjectTransform(const float time)
|
void AbcObjectReader::setupObjectTransform(const float time)
|
||||||
{
|
{
|
||||||
bool is_constant = false;
|
bool is_constant = false;
|
||||||
@@ -166,16 +166,32 @@ void AbcObjectReader::setupObjectTransform(const float time)
|
|||||||
BKE_object_to_mat4(m_object, m_object->obmat);
|
BKE_object_to_mat4(m_object, m_object->obmat);
|
||||||
|
|
||||||
if (!is_constant || m_settings->always_add_cache_reader) {
|
if (!is_constant || m_settings->always_add_cache_reader) {
|
||||||
bConstraint *con = BKE_constraint_add_for_object(
|
bTransformCacheConstraint *constraint = getOrCreateConstraint();
|
||||||
m_object, nullptr, CONSTRAINT_TYPE_TRANSFORM_CACHE);
|
BLI_strncpy(constraint->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
||||||
bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
|
|
||||||
BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
|
||||||
|
|
||||||
data->cache_file = m_settings->cache_file;
|
|
||||||
id_us_plus(&data->cache_file->id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bTransformCacheConstraint *AbcObjectReader::getOrCreateConstraint()
|
||||||
|
{
|
||||||
|
if (m_iobject.isInstanceRoot()) {
|
||||||
|
/* As this is an instance we may already have created a constraint when duplicating the source
|
||||||
|
* object, if so return it. Note that it is possible for an instance to have an animated
|
||||||
|
* transform, but not for the source object. */
|
||||||
|
bConstraint *constraint = static_cast<bConstraint *>(m_object->constraints.last);
|
||||||
|
if (constraint && constraint->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
|
||||||
|
return static_cast<bTransformCacheConstraint *>(constraint->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new constraint. */
|
||||||
|
bConstraint *constraint = BKE_constraint_add_for_object(
|
||||||
|
m_object, nullptr, CONSTRAINT_TYPE_TRANSFORM_CACHE);
|
||||||
|
bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(constraint->data);
|
||||||
|
data->cache_file = m_settings->cache_file;
|
||||||
|
id_us_plus(&data->cache_file->id);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
Alembic::AbcGeom::IXform AbcObjectReader::xform()
|
Alembic::AbcGeom::IXform AbcObjectReader::xform()
|
||||||
{
|
{
|
||||||
/* Check that we have an empty object (locator, bone head/tail...). */
|
/* Check that we have an empty object (locator, bone head/tail...). */
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
|
|
||||||
#include "DNA_ID.h"
|
#include "DNA_ID.h"
|
||||||
|
|
||||||
|
struct bTransformCacheConstraint;
|
||||||
struct CacheFile;
|
struct CacheFile;
|
||||||
|
struct GeometrySet;
|
||||||
struct Main;
|
struct Main;
|
||||||
struct Mesh;
|
struct Mesh;
|
||||||
struct Object;
|
struct Object;
|
||||||
@@ -19,6 +21,9 @@ using Alembic::AbcCoreAbstract::chrono_t;
|
|||||||
|
|
||||||
namespace blender::io::alembic {
|
namespace blender::io::alembic {
|
||||||
|
|
||||||
|
class AbcReaderManager;
|
||||||
|
class AttributeSelector;
|
||||||
|
|
||||||
struct ImportSettings {
|
struct ImportSettings {
|
||||||
bool do_convert_mat;
|
bool do_convert_mat;
|
||||||
float conversion_mat[4][4];
|
float conversion_mat[4][4];
|
||||||
@@ -37,7 +42,6 @@ struct ImportSettings {
|
|||||||
int read_flag;
|
int read_flag;
|
||||||
|
|
||||||
/* From CacheFile and MeshSeqCacheModifierData */
|
/* From CacheFile and MeshSeqCacheModifierData */
|
||||||
std::string velocity_name;
|
|
||||||
float velocity_scale;
|
float velocity_scale;
|
||||||
|
|
||||||
bool validate_meshes;
|
bool validate_meshes;
|
||||||
@@ -55,7 +59,6 @@ struct ImportSettings {
|
|||||||
sequence_len(1),
|
sequence_len(1),
|
||||||
sequence_offset(0),
|
sequence_offset(0),
|
||||||
read_flag(0),
|
read_flag(0),
|
||||||
velocity_name(""),
|
|
||||||
velocity_scale(1.0f),
|
velocity_scale(1.0f),
|
||||||
validate_meshes(false),
|
validate_meshes(false),
|
||||||
always_add_cache_reader(false),
|
always_add_cache_reader(false),
|
||||||
@@ -131,17 +134,20 @@ class AbcObjectReader {
|
|||||||
const Object *const ob,
|
const Object *const ob,
|
||||||
const char **err_str) const = 0;
|
const char **err_str) const = 0;
|
||||||
|
|
||||||
virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0;
|
virtual void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) = 0;
|
||||||
|
|
||||||
virtual struct Mesh *read_mesh(struct Mesh *mesh,
|
|
||||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
|
||||||
int read_flag,
|
|
||||||
const char *velocity_name,
|
|
||||||
float velocity_scale,
|
|
||||||
const char **err_str);
|
|
||||||
virtual bool topology_changed(Mesh *existing_mesh,
|
virtual bool topology_changed(Mesh *existing_mesh,
|
||||||
const Alembic::Abc::ISampleSelector &sample_sel);
|
const Alembic::Abc::ISampleSelector &sample_sel);
|
||||||
|
|
||||||
|
virtual void read_geometry(GeometrySet &geometry_set,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
|
const AttributeSelector *attribute_selector,
|
||||||
|
int read_flag,
|
||||||
|
const float velocity_scale,
|
||||||
|
const char **err_str);
|
||||||
|
|
||||||
/** Reads the object matrix and sets up an object transform if animated. */
|
/** Reads the object matrix and sets up an object transform if animated. */
|
||||||
void setupObjectTransform(float time);
|
void setupObjectTransform(float time);
|
||||||
|
|
||||||
@@ -159,6 +165,9 @@ class AbcObjectReader {
|
|||||||
protected:
|
protected:
|
||||||
/** Determine whether we can inherit our parent's XForm. */
|
/** Determine whether we can inherit our parent's XForm. */
|
||||||
void determine_inherits_xform();
|
void determine_inherits_xform();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bTransformCacheConstraint *getOrCreateConstraint();
|
||||||
};
|
};
|
||||||
|
|
||||||
Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, float time);
|
Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, float time);
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "abc_reader_points.h"
|
#include "abc_reader_points.h"
|
||||||
|
#include "abc_axis_conversion.h"
|
||||||
#include "abc_reader_mesh.h"
|
#include "abc_reader_mesh.h"
|
||||||
#include "abc_reader_transform.h"
|
#include "abc_reader_transform.h"
|
||||||
#include "abc_util.h"
|
#include "abc_util.h"
|
||||||
@@ -13,15 +14,21 @@
|
|||||||
#include "DNA_mesh_types.h"
|
#include "DNA_mesh_types.h"
|
||||||
#include "DNA_modifier_types.h"
|
#include "DNA_modifier_types.h"
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
|
#include "DNA_pointcloud_types.h"
|
||||||
|
|
||||||
#include "BKE_customdata.h"
|
#include "BKE_customdata.h"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
|
#include "BKE_lib_id.h"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
#include "BKE_object.h"
|
#include "BKE_object.h"
|
||||||
|
#include "BKE_pointcloud.h"
|
||||||
|
|
||||||
using Alembic::AbcGeom::kWrapExisting;
|
using Alembic::AbcGeom::kWrapExisting;
|
||||||
using Alembic::AbcGeom::N3fArraySamplePtr;
|
using Alembic::AbcGeom::N3fArraySamplePtr;
|
||||||
using Alembic::AbcGeom::P3fArraySamplePtr;
|
using Alembic::AbcGeom::P3fArraySamplePtr;
|
||||||
|
|
||||||
|
using namespace Alembic::AbcGeom;
|
||||||
|
|
||||||
using Alembic::AbcGeom::ICompoundProperty;
|
using Alembic::AbcGeom::ICompoundProperty;
|
||||||
using Alembic::AbcGeom::IN3fArrayProperty;
|
using Alembic::AbcGeom::IN3fArrayProperty;
|
||||||
using Alembic::AbcGeom::IPoints;
|
using Alembic::AbcGeom::IPoints;
|
||||||
@@ -55,7 +62,7 @@ bool AbcPointsReader::accepts_object_type(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ob->type != OB_MESH) {
|
if (ob->type != OB_POINTCLOUD) {
|
||||||
*err_str = "Object type mismatch, Alembic object path points to Points.";
|
*err_str = "Object type mismatch, Alembic object path points to Points.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -63,58 +70,89 @@ bool AbcPointsReader::accepts_object_type(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
void AbcPointsReader::readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager & /*manager*/,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||||
{
|
{
|
||||||
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
PointCloud *point_cloud = static_cast<PointCloud *>(
|
||||||
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, "", 0.0f, nullptr);
|
BKE_pointcloud_add_default(bmain, m_data_name.c_str()));
|
||||||
|
|
||||||
if (read_mesh != mesh) {
|
GeometrySet geometry_set = GeometrySet::create_with_pointcloud(point_cloud,
|
||||||
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true);
|
GeometryOwnershipType::Editable);
|
||||||
|
read_geometry(geometry_set, sample_sel, nullptr, 0, 0.0f, nullptr);
|
||||||
|
|
||||||
|
PointCloud *read_point_cloud =
|
||||||
|
geometry_set.get_component_for_write<PointCloudComponent>().release();
|
||||||
|
|
||||||
|
if (read_point_cloud != point_cloud) {
|
||||||
|
BKE_pointcloud_nomain_to_pointcloud(read_point_cloud, point_cloud, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_settings->validate_meshes) {
|
m_object = BKE_object_add_only_object(bmain, OB_POINTCLOUD, m_object_name.c_str());
|
||||||
BKE_mesh_validate(mesh, false, false);
|
m_object->data = point_cloud;
|
||||||
}
|
|
||||||
|
|
||||||
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
|
||||||
m_object->data = mesh;
|
|
||||||
|
|
||||||
if (m_settings->always_add_cache_reader || has_animations(m_schema, m_settings)) {
|
if (m_settings->always_add_cache_reader || has_animations(m_schema, m_settings)) {
|
||||||
addCacheModifier();
|
addCacheModifier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_points_sample(const IPointsSchema &schema,
|
static void read_points_interp(const P3fArraySamplePtr positions,
|
||||||
const ISampleSelector &selector,
|
const P3fArraySamplePtr ceil_positions,
|
||||||
CDStreamConfig &config)
|
const float weight,
|
||||||
|
float3 *r_points)
|
||||||
|
{
|
||||||
|
float3 tmp;
|
||||||
|
for (size_t i = 0; i < positions->size(); i++) {
|
||||||
|
const Imath::V3f &floor_pos = (*positions)[i];
|
||||||
|
const Imath::V3f &ceil_pos = (*ceil_positions)[i];
|
||||||
|
interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight);
|
||||||
|
copy_zup_from_yup(r_points[i], (*positions)[i].getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_points(const P3fArraySamplePtr positions, float3 *r_points)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < positions->size(); i++) {
|
||||||
|
copy_zup_from_yup(r_points[i], (*positions)[i].getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_points_sample(const IPointsSchema &schema,
|
||||||
|
const ISampleSelector &selector,
|
||||||
|
CDStreamConfig &config,
|
||||||
|
float3 *r_points)
|
||||||
{
|
{
|
||||||
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
|
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
|
||||||
|
|
||||||
const P3fArraySamplePtr &positions = sample.getPositions();
|
const P3fArraySamplePtr &positions = sample.getPositions();
|
||||||
|
|
||||||
ICompoundProperty prop = schema.getArbGeomParams();
|
ICompoundProperty prop = schema.getArbGeomParams();
|
||||||
N3fArraySamplePtr vnormals;
|
|
||||||
|
|
||||||
if (has_property(prop, "N")) {
|
Alembic::AbcGeom::index_t i0, i1;
|
||||||
const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>(
|
const float weight = get_weight_and_index(
|
||||||
selector.getRequestedTime());
|
config.time, schema.getTimeSampling(), schema.getNumSamples(), i0, i1);
|
||||||
const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime);
|
|
||||||
|
|
||||||
if (normals_prop) {
|
if (config.use_vertex_interpolation && weight != 0.0f) {
|
||||||
vnormals = normals_prop.getValue(selector);
|
Alembic::AbcGeom::IPointsSchema::Sample ceil_sample;
|
||||||
}
|
schema.get(ceil_sample, Alembic::Abc::ISampleSelector(i1));
|
||||||
|
P3fArraySamplePtr ceil_positions = ceil_sample.getPositions();
|
||||||
|
|
||||||
|
read_points_interp(positions, ceil_positions, weight, r_points);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_mverts(*config.mesh, positions, vnormals);
|
read_points(positions, r_points);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
|
void AbcPointsReader::read_geometry(GeometrySet &geometry_set,
|
||||||
const ISampleSelector &sample_sel,
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
int read_flag,
|
const AttributeSelector *attribute_selector,
|
||||||
const char * /*velocity_name*/,
|
int read_flag,
|
||||||
const float /*velocity_scale*/,
|
const float velocity_scale,
|
||||||
const char **err_str)
|
const char **err_str)
|
||||||
{
|
{
|
||||||
|
assert(geometry_set.has_pointcloud());
|
||||||
|
|
||||||
IPointsSchema::Sample sample;
|
IPointsSchema::Sample sample;
|
||||||
try {
|
try {
|
||||||
sample = m_schema.getValue(sample_sel);
|
sample = m_schema.getValue(sample_sel);
|
||||||
@@ -126,23 +164,64 @@ struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
|
|||||||
m_schema.getName().c_str(),
|
m_schema.getName().c_str(),
|
||||||
sample_sel.getRequestedTime(),
|
sample_sel.getRequestedTime(),
|
||||||
ex.what());
|
ex.what());
|
||||||
return existing_mesh;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointCloud *existing_point_cloud = geometry_set.get_pointcloud_for_write();
|
||||||
|
PointCloud *point_cloud = existing_point_cloud;
|
||||||
|
|
||||||
const P3fArraySamplePtr &positions = sample.getPositions();
|
const P3fArraySamplePtr &positions = sample.getPositions();
|
||||||
|
|
||||||
Mesh *new_mesh = nullptr;
|
const IFloatGeomParam widths_param = m_schema.getWidthsParam();
|
||||||
|
FloatArraySamplePtr radiuses;
|
||||||
|
|
||||||
if (existing_mesh->totvert != positions->size()) {
|
if (widths_param.valid()) {
|
||||||
new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0, 0);
|
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
|
||||||
|
radiuses = wsample.getVals();
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
|
if (point_cloud->totpoint != positions->size()) {
|
||||||
const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
|
point_cloud = BKE_pointcloud_new_nomain(positions->size());
|
||||||
CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
|
}
|
||||||
read_points_sample(m_schema, sample_sel, config);
|
|
||||||
|
|
||||||
return mesh_to_export;
|
CDStreamConfig config;
|
||||||
|
config.id = &point_cloud->id;
|
||||||
|
BKE_id_attribute_get_domains(config.id, config.domain_info);
|
||||||
|
config.attr_selector = attribute_selector;
|
||||||
|
config.time = sample_sel.getRequestedTime();
|
||||||
|
config.use_vertex_interpolation = (read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES) != 0;
|
||||||
|
config.modifier_error_message = err_str;
|
||||||
|
|
||||||
|
read_points_sample(m_schema, sample_sel, config, reinterpret_cast<float3 *>(point_cloud->co));
|
||||||
|
|
||||||
|
if (radiuses) {
|
||||||
|
for (size_t i = 0; i < radiuses->size(); i++) {
|
||||||
|
point_cloud->radius[i] = (*radiuses)[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < point_cloud->totpoint; i++) {
|
||||||
|
point_cloud->radius[i] = 0.01f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64ArraySamplePtr ids = sample.getIds();
|
||||||
|
if (ids && ids->size() == positions->size()) {
|
||||||
|
CustomDataLayer *ids_layer = BKE_id_attribute_ensure(
|
||||||
|
&point_cloud->id, "ids", CD_PROP_INT32, ATTR_DOMAIN_POINT, nullptr);
|
||||||
|
int *ids_layer_data = static_cast<int *>(ids_layer->data);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ids->size(); i++) {
|
||||||
|
ids_layer_data[i] = static_cast<int>((*ids)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attributes */
|
||||||
|
read_arbitrary_attributes(config, m_schema, {}, sample_sel, velocity_scale);
|
||||||
|
|
||||||
|
if (point_cloud != existing_point_cloud) {
|
||||||
|
geometry_set.replace_pointcloud(point_cloud);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
@@ -23,18 +23,16 @@ class AbcPointsReader final : public AbcObjectReader {
|
|||||||
const Object *const ob,
|
const Object *const ob,
|
||||||
const char **err_str) const override;
|
const char **err_str) const override;
|
||||||
|
|
||||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
|
|
||||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
void read_geometry(GeometrySet &geometry_set,
|
||||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||||
int read_flag,
|
const AttributeSelector *attribute_selector,
|
||||||
const char *velocity_name,
|
int read_flag,
|
||||||
float velocity_scale,
|
const float velocity_scale,
|
||||||
const char **err_str) override;
|
const char **err_str) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
|
|
||||||
const Alembic::AbcGeom::ISampleSelector &selector,
|
|
||||||
CDStreamConfig &config);
|
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
@@ -55,7 +55,9 @@ bool AbcEmptyReader::accepts_object_type(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbcEmptyReader::readObjectData(Main *bmain, const ISampleSelector &UNUSED(sample_sel))
|
void AbcEmptyReader::readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager & /*manager*/,
|
||||||
|
const ISampleSelector &UNUSED(sample_sel))
|
||||||
{
|
{
|
||||||
m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
|
m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
|
||||||
m_object->data = nullptr;
|
m_object->data = nullptr;
|
||||||
|
@@ -22,7 +22,9 @@ class AbcEmptyReader final : public AbcObjectReader {
|
|||||||
const Object *const ob,
|
const Object *const ob,
|
||||||
const char **err_str) const override;
|
const char **err_str) const override;
|
||||||
|
|
||||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
void readObjectData(Main *bmain,
|
||||||
|
const AbcReaderManager &manager,
|
||||||
|
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::io::alembic
|
} // namespace blender::io::alembic
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include "abc_reader_archive.h"
|
#include "abc_reader_archive.h"
|
||||||
#include "abc_reader_camera.h"
|
#include "abc_reader_camera.h"
|
||||||
#include "abc_reader_curves.h"
|
#include "abc_reader_curves.h"
|
||||||
|
#include "abc_reader_manager.h"
|
||||||
#include "abc_reader_mesh.h"
|
#include "abc_reader_mesh.h"
|
||||||
#include "abc_reader_nurbs.h"
|
#include "abc_reader_nurbs.h"
|
||||||
#include "abc_reader_points.h"
|
#include "abc_reader_points.h"
|
||||||
@@ -211,7 +212,7 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string
|
|||||||
* Generates an AbcObjectReader for this Alembic object and its children.
|
* Generates an AbcObjectReader for this Alembic object and its children.
|
||||||
*
|
*
|
||||||
* \param object: The Alembic IObject to visit.
|
* \param object: The Alembic IObject to visit.
|
||||||
* \param readers: The created AbcObjectReader * will be appended to this vector.
|
* \param manager: The manager responsible for creating the readers.
|
||||||
* \param settings: Import settings, not used directly but passed to the
|
* \param settings: Import settings, not used directly but passed to the
|
||||||
* AbcObjectReader subclass constructors.
|
* AbcObjectReader subclass constructors.
|
||||||
* \param r_assign_as_parent: Return parameter, contains a list of reader
|
* \param r_assign_as_parent: Return parameter, contains a list of reader
|
||||||
@@ -229,7 +230,7 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string
|
|||||||
* them in sync. */
|
* them in sync. */
|
||||||
static std::pair<bool, AbcObjectReader *> visit_object(
|
static std::pair<bool, AbcObjectReader *> visit_object(
|
||||||
const IObject &object,
|
const IObject &object,
|
||||||
AbcObjectReader::ptr_vector &readers,
|
AbcReaderManager &manager,
|
||||||
ImportSettings &settings,
|
ImportSettings &settings,
|
||||||
AbcObjectReader::ptr_vector &r_assign_as_parent)
|
AbcObjectReader::ptr_vector &r_assign_as_parent)
|
||||||
{
|
{
|
||||||
@@ -254,7 +255,7 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
|||||||
|
|
||||||
/* TODO: When we only support C++11, use std::tie() instead. */
|
/* TODO: When we only support C++11, use std::tie() instead. */
|
||||||
std::pair<bool, AbcObjectReader *> child_result;
|
std::pair<bool, AbcObjectReader *> child_result;
|
||||||
child_result = visit_object(ichild, readers, settings, assign_as_parent);
|
child_result = visit_object(ichild, manager, settings, assign_as_parent);
|
||||||
|
|
||||||
bool child_claims_this_object = child_result.first;
|
bool child_claims_this_object = child_result.first;
|
||||||
AbcObjectReader *child_reader = child_result.second;
|
AbcObjectReader *child_reader = child_result.second;
|
||||||
@@ -299,15 +300,15 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (create_empty) {
|
if (create_empty) {
|
||||||
reader = new AbcEmptyReader(object, settings);
|
reader = manager.create<AbcEmptyReader>(object, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IPolyMesh::matches(md)) {
|
else if (IPolyMesh::matches(md)) {
|
||||||
reader = new AbcMeshReader(object, settings);
|
reader = manager.create<AbcMeshReader>(object, settings);
|
||||||
parent_is_part_of_this_object = true;
|
parent_is_part_of_this_object = true;
|
||||||
}
|
}
|
||||||
else if (ISubD::matches(md)) {
|
else if (ISubD::matches(md)) {
|
||||||
reader = new AbcSubDReader(object, settings);
|
reader = manager.create<AbcSubDReader>(object, settings);
|
||||||
parent_is_part_of_this_object = true;
|
parent_is_part_of_this_object = true;
|
||||||
}
|
}
|
||||||
else if (INuPatch::matches(md)) {
|
else if (INuPatch::matches(md)) {
|
||||||
@@ -318,16 +319,16 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
|||||||
* Blender. Need to figure out exactly how these points are
|
* Blender. Need to figure out exactly how these points are
|
||||||
* duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
|
* duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
|
||||||
* Until this is fixed, disabling NURBS reading. */
|
* Until this is fixed, disabling NURBS reading. */
|
||||||
reader = new AbcNurbsReader(object, settings);
|
reader = manager.create<AbcNurbsReader>(object, settings);
|
||||||
parent_is_part_of_this_object = true;
|
parent_is_part_of_this_object = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (ICamera::matches(md)) {
|
else if (ICamera::matches(md)) {
|
||||||
reader = new AbcCameraReader(object, settings);
|
reader = manager.create<AbcCameraReader>(object, settings);
|
||||||
parent_is_part_of_this_object = true;
|
parent_is_part_of_this_object = true;
|
||||||
}
|
}
|
||||||
else if (IPoints::matches(md)) {
|
else if (IPoints::matches(md)) {
|
||||||
reader = new AbcPointsReader(object, settings);
|
reader = manager.create<AbcPointsReader>(object, settings);
|
||||||
parent_is_part_of_this_object = true;
|
parent_is_part_of_this_object = true;
|
||||||
}
|
}
|
||||||
else if (IMaterial::matches(md)) {
|
else if (IMaterial::matches(md)) {
|
||||||
@@ -340,7 +341,7 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
|||||||
/* Pass, those are handled in the mesh reader. */
|
/* Pass, those are handled in the mesh reader. */
|
||||||
}
|
}
|
||||||
else if (ICurves::matches(md)) {
|
else if (ICurves::matches(md)) {
|
||||||
reader = new AbcCurveReader(object, settings);
|
reader = manager.create<AbcCurveReader>(object, settings);
|
||||||
parent_is_part_of_this_object = true;
|
parent_is_part_of_this_object = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -353,7 +354,6 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
|||||||
* not claimed as part of any child Alembic object. */
|
* not claimed as part of any child Alembic object. */
|
||||||
BLI_assert(claiming_child_readers.empty());
|
BLI_assert(claiming_child_readers.empty());
|
||||||
|
|
||||||
readers.push_back(reader);
|
|
||||||
reader->incref();
|
reader->incref();
|
||||||
|
|
||||||
CacheObjectPath *abc_path = static_cast<CacheObjectPath *>(
|
CacheObjectPath *abc_path = static_cast<CacheObjectPath *>(
|
||||||
@@ -423,7 +423,7 @@ struct ImportJobData {
|
|||||||
ImportSettings settings;
|
ImportSettings settings;
|
||||||
|
|
||||||
ArchiveReader *archive;
|
ArchiveReader *archive;
|
||||||
std::vector<AbcObjectReader *> readers;
|
AbcReaderManager reader_manager;
|
||||||
|
|
||||||
short *stop;
|
short *stop;
|
||||||
short *do_update;
|
short *do_update;
|
||||||
@@ -475,7 +475,8 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
|||||||
|
|
||||||
/* Parse Alembic Archive. */
|
/* Parse Alembic Archive. */
|
||||||
AbcObjectReader::ptr_vector assign_as_parent;
|
AbcObjectReader::ptr_vector assign_as_parent;
|
||||||
visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent);
|
IObject root = archive->getTop();
|
||||||
|
visit_object(archive->getTop(), data->reader_manager, data->settings, assign_as_parent);
|
||||||
|
|
||||||
/* There shouldn't be any orphans. */
|
/* There shouldn't be any orphans. */
|
||||||
BLI_assert(assign_as_parent.empty());
|
BLI_assert(assign_as_parent.empty());
|
||||||
@@ -490,19 +491,16 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
|||||||
|
|
||||||
/* Create objects and set scene frame range. */
|
/* Create objects and set scene frame range. */
|
||||||
|
|
||||||
const float size = static_cast<float>(data->readers.size());
|
const float size = static_cast<float>(data->reader_manager.all_readers().size());
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
chrono_t min_time = std::numeric_limits<chrono_t>::max();
|
chrono_t min_time = std::numeric_limits<chrono_t>::max();
|
||||||
chrono_t max_time = std::numeric_limits<chrono_t>::min();
|
chrono_t max_time = std::numeric_limits<chrono_t>::min();
|
||||||
|
|
||||||
ISampleSelector sample_sel(0.0f);
|
ISampleSelector sample_sel(0.0f);
|
||||||
std::vector<AbcObjectReader *>::iterator iter;
|
for (AbcObjectReader *reader : data->reader_manager.data_readers()) {
|
||||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
|
||||||
AbcObjectReader *reader = *iter;
|
|
||||||
|
|
||||||
if (reader->valid()) {
|
if (reader->valid()) {
|
||||||
reader->readObjectData(data->bmain, sample_sel);
|
reader->readObjectData(data->bmain, data->reader_manager, sample_sel);
|
||||||
|
|
||||||
min_time = std::min(min_time, reader->minTime());
|
min_time = std::min(min_time, reader->minTime());
|
||||||
max_time = std::max(max_time, reader->maxTime());
|
max_time = std::max(max_time, reader->maxTime());
|
||||||
@@ -537,8 +535,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Setup parenthood. */
|
/* Setup parenthood. */
|
||||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
for (AbcObjectReader *reader : data->reader_manager.data_readers()) {
|
||||||
const AbcObjectReader *reader = *iter;
|
|
||||||
const AbcObjectReader *parent_reader = reader->parent_reader;
|
const AbcObjectReader *parent_reader = reader->parent_reader;
|
||||||
Object *ob = reader->object();
|
Object *ob = reader->object();
|
||||||
|
|
||||||
@@ -552,8 +549,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
|||||||
|
|
||||||
/* Setup transformations and constraints. */
|
/* Setup transformations and constraints. */
|
||||||
i = 0;
|
i = 0;
|
||||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
for (AbcObjectReader *reader : data->reader_manager.data_readers()) {
|
||||||
AbcObjectReader *reader = *iter;
|
|
||||||
reader->setupObjectTransform(0.0f);
|
reader->setupObjectTransform(0.0f);
|
||||||
|
|
||||||
*data->progress = 0.7f + 0.3f * (++i / size);
|
*data->progress = 0.7f + 0.3f * (++i / size);
|
||||||
@@ -572,12 +568,10 @@ static void import_endjob(void *user_data)
|
|||||||
|
|
||||||
ImportJobData *data = static_cast<ImportJobData *>(user_data);
|
ImportJobData *data = static_cast<ImportJobData *>(user_data);
|
||||||
|
|
||||||
std::vector<AbcObjectReader *>::iterator iter;
|
|
||||||
|
|
||||||
/* Delete objects on cancellation. */
|
/* Delete objects on cancellation. */
|
||||||
if (data->was_cancelled) {
|
if (data->was_cancelled) {
|
||||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
for (AbcObjectReader *reader : data->reader_manager.all_readers()) {
|
||||||
Object *ob = (*iter)->object();
|
Object *ob = reader->object();
|
||||||
|
|
||||||
/* It's possible that cancellation occurred between the creation of
|
/* It's possible that cancellation occurred between the creation of
|
||||||
* the reader and the creation of the Blender object. */
|
* the reader and the creation of the Blender object. */
|
||||||
@@ -598,8 +592,8 @@ static void import_endjob(void *user_data)
|
|||||||
|
|
||||||
lc = BKE_layer_collection_get_active(view_layer);
|
lc = BKE_layer_collection_get_active(view_layer);
|
||||||
|
|
||||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
for (AbcObjectReader *reader : data->reader_manager.data_readers()) {
|
||||||
Object *ob = (*iter)->object();
|
Object *ob = reader->object();
|
||||||
|
|
||||||
BKE_collection_object_add(data->bmain, lc->collection, ob);
|
BKE_collection_object_add(data->bmain, lc->collection, ob);
|
||||||
|
|
||||||
@@ -614,6 +608,24 @@ static void import_endjob(void *user_data)
|
|||||||
ID_RECALC_BASE_FLAGS);
|
ID_RECALC_BASE_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Finally, create instances. */
|
||||||
|
for (AbcObjectReader *reader : data->reader_manager.instance_readers()) {
|
||||||
|
if (!reader->valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
reader->readObjectData(data->bmain, data->reader_manager, {});
|
||||||
|
/* We assume that the instance's parent is the same as that of the source object, so we do
|
||||||
|
* not setup parenthood. */
|
||||||
|
reader->setupObjectTransform(0.0f);
|
||||||
|
|
||||||
|
Object *ob = reader->object();
|
||||||
|
BKE_collection_object_add(data->bmain, lc->collection, ob);
|
||||||
|
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||||
|
|
||||||
|
BKE_main_id_newptr_and_tag_clear(data->bmain);
|
||||||
|
}
|
||||||
|
|
||||||
DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS);
|
DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS);
|
||||||
DEG_relations_tag_update(data->bmain);
|
DEG_relations_tag_update(data->bmain);
|
||||||
|
|
||||||
@@ -624,8 +636,7 @@ static void import_endjob(void *user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
for (AbcObjectReader *reader : data->reader_manager.all_readers()) {
|
||||||
AbcObjectReader *reader = *iter;
|
|
||||||
reader->decref();
|
reader->decref();
|
||||||
|
|
||||||
if (reader->refcount() == 0) {
|
if (reader->refcount() == 0) {
|
||||||
@@ -781,23 +792,28 @@ static ISampleSelector sample_selector_for_time(float time)
|
|||||||
return ISampleSelector(time, ISampleSelector::kFloorIndex);
|
return ISampleSelector(time, ISampleSelector::kFloorIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *ABC_read_mesh(CacheReader *reader,
|
void ABC_read_geometry(CacheReader *reader,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
Mesh *existing_mesh,
|
GeometrySet &geometry_set,
|
||||||
const float time,
|
const ABCReadParams *params,
|
||||||
const char **err_str,
|
const char **err_str)
|
||||||
const int read_flag,
|
|
||||||
const char *velocity_name,
|
|
||||||
const float velocity_scale)
|
|
||||||
{
|
{
|
||||||
AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
|
AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
|
||||||
if (abc_reader == nullptr) {
|
if (abc_reader == nullptr) {
|
||||||
return nullptr;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ISampleSelector sample_sel = sample_selector_for_time(time);
|
AttributeSelector attribute_selector(params->mappings);
|
||||||
return abc_reader->read_mesh(
|
attribute_selector.set_velocity_attribute(params->velocity_name);
|
||||||
existing_mesh, sample_sel, read_flag, velocity_name, velocity_scale, err_str);
|
attribute_selector.set_read_flags(params->read_flags);
|
||||||
|
|
||||||
|
ISampleSelector sample_sel = sample_selector_for_time(params->time);
|
||||||
|
abc_reader->read_geometry(geometry_set,
|
||||||
|
sample_sel,
|
||||||
|
&attribute_selector,
|
||||||
|
params->read_flags,
|
||||||
|
params->velocity_scale,
|
||||||
|
err_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ABC_mesh_topology_changed(
|
bool ABC_mesh_topology_changed(
|
||||||
|
@@ -25,6 +25,7 @@ set(INC
|
|||||||
../../bmesh
|
../../bmesh
|
||||||
../../depsgraph
|
../../depsgraph
|
||||||
../../editors/include
|
../../editors/include
|
||||||
|
../../functions
|
||||||
../../makesdna
|
../../makesdna
|
||||||
../../makesrna
|
../../makesrna
|
||||||
../../windowmanager
|
../../windowmanager
|
||||||
|
@@ -420,20 +420,20 @@ static USDPrimReader *get_usd_reader(CacheReader *reader, Object * /* ob */, con
|
|||||||
return usd_reader;
|
return usd_reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Mesh *USD_read_mesh(struct CacheReader *reader,
|
void USD_read_geometry(CacheReader *reader,
|
||||||
struct Object *ob,
|
Object *ob,
|
||||||
struct Mesh *existing_mesh,
|
GeometrySet &geometry_set,
|
||||||
const float time,
|
const float time,
|
||||||
const char **err_str,
|
const char **err_str,
|
||||||
const int read_flag)
|
const int read_flag)
|
||||||
{
|
{
|
||||||
USDGeomReader *usd_reader = dynamic_cast<USDGeomReader *>(get_usd_reader(reader, ob, err_str));
|
USDGeomReader *usd_reader = dynamic_cast<USDGeomReader *>(get_usd_reader(reader, ob, err_str));
|
||||||
|
|
||||||
if (usd_reader == nullptr) {
|
if (usd_reader == nullptr) {
|
||||||
return nullptr;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return usd_reader->read_mesh(existing_mesh, time, read_flag, err_str);
|
return usd_reader->read_geometry(geometry_set, time, read_flag, err_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USD_mesh_topology_changed(
|
bool USD_mesh_topology_changed(
|
||||||
|
@@ -5,8 +5,10 @@
|
|||||||
#include "usd_reader_curve.h"
|
#include "usd_reader_curve.h"
|
||||||
|
|
||||||
#include "BKE_curve.h"
|
#include "BKE_curve.h"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
#include "BKE_object.h"
|
#include "BKE_object.h"
|
||||||
|
#include "BKE_spline.hh"
|
||||||
|
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
|
|
||||||
@@ -161,15 +163,39 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh,
|
static bool topology_changed(CurveEval *curve_eval, const pxr::VtIntArray &usdCounts)
|
||||||
const double motionSampleTime,
|
|
||||||
const int /* read_flag */,
|
|
||||||
const char ** /* err_str */)
|
|
||||||
{
|
{
|
||||||
if (!curve_prim_) {
|
if (!curve_eval) {
|
||||||
return existing_mesh;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (curve_eval->splines().size() != usdCounts.size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int curve_idx = 0;
|
||||||
|
for (const SplinePtr &spline : curve_eval->splines()) {
|
||||||
|
const int num_in_usd = usdCounts[curve_idx++];
|
||||||
|
const int num_in_blender = spline->positions().size();
|
||||||
|
|
||||||
|
if (num_in_usd != num_in_blender) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USDCurvesReader::read_geometry(GeometrySet &geometry_set,
|
||||||
|
double motionSampleTime,
|
||||||
|
int /* read_flag */,
|
||||||
|
const char ** /* err_str */)
|
||||||
|
{
|
||||||
|
if (!curve_prim_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
|
pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
|
||||||
pxr::UsdAttribute vertexAttr = curve_prim_.GetCurveVertexCountsAttr();
|
pxr::UsdAttribute vertexAttr = curve_prim_.GetCurveVertexCountsAttr();
|
||||||
pxr::UsdAttribute pointsAttr = curve_prim_.GetPointsAttr();
|
pxr::UsdAttribute pointsAttr = curve_prim_.GetPointsAttr();
|
||||||
@@ -177,62 +203,37 @@ Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh,
|
|||||||
pxr::VtIntArray usdCounts;
|
pxr::VtIntArray usdCounts;
|
||||||
|
|
||||||
vertexAttr.Get(&usdCounts, motionSampleTime);
|
vertexAttr.Get(&usdCounts, motionSampleTime);
|
||||||
int num_subcurves = usdCounts.size();
|
|
||||||
|
|
||||||
pxr::VtVec3fArray usdPoints;
|
pxr::VtVec3fArray usdPoints;
|
||||||
pointsAttr.Get(&usdPoints, motionSampleTime);
|
pointsAttr.Get(&usdPoints, motionSampleTime);
|
||||||
|
|
||||||
int vertex_idx = 0;
|
int vertex_idx = 0;
|
||||||
int curve_idx;
|
int curve_idx;
|
||||||
Curve *curve = static_cast<Curve *>(object_->data);
|
CurveEval *curve_eval = geometry_set.get_curve_for_write();
|
||||||
|
|
||||||
const int curve_count = BLI_listbase_count(&curve->nurb);
|
if (blender::io::usd::topology_changed(curve_eval, usdCounts)) {
|
||||||
bool same_topology = curve_count == num_subcurves;
|
Curve *curve = static_cast<Curve *>(object_->data);
|
||||||
|
|
||||||
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);
|
BKE_nurbList_free(&curve->nurb);
|
||||||
read_curve_sample(curve, motionSampleTime);
|
read_curve_sample(curve, motionSampleTime);
|
||||||
|
|
||||||
|
std::unique_ptr<CurveEval> new_curve_eval = curve_eval_from_dna_curve(*curve);
|
||||||
|
geometry_set.replace_curve(new_curve_eval.release(), GeometryOwnershipType::Editable);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
BLI_assert_msg(curve_eval, "curve_eval is null although the topology is the same !");
|
||||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
const int curve_count = curve_eval->splines().size();
|
||||||
const int totpoint = usdCounts[curve_idx];
|
for (curve_idx = 0; curve_idx < curve_count; curve_idx++) {
|
||||||
|
Spline *spline = curve_eval->splines()[curve_idx].get();
|
||||||
|
|
||||||
if (nurbs->bp) {
|
for (float3 &position : spline->positions()) {
|
||||||
BPoint *point = nurbs->bp;
|
position.x = usdPoints[vertex_idx][0];
|
||||||
|
position.y = usdPoints[vertex_idx][0];
|
||||||
for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
|
position.z = usdPoints[vertex_idx][0];
|
||||||
point->vec[0] = usdPoints[vertex_idx][0];
|
vertex_idx++;
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return BKE_mesh_new_nomain_from_curve(object_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blender::io::usd
|
} // namespace blender::io::usd
|
||||||
|
@@ -35,10 +35,10 @@ class USDCurvesReader : public USDGeomReader {
|
|||||||
|
|
||||||
void read_curve_sample(Curve *cu, double motionSampleTime);
|
void read_curve_sample(Curve *cu, double motionSampleTime);
|
||||||
|
|
||||||
Mesh *read_mesh(struct Mesh *existing_mesh,
|
void read_geometry(GeometrySet &geometry_set,
|
||||||
double motionSampleTime,
|
double motionSampleTime,
|
||||||
int read_flag,
|
int read_flag,
|
||||||
const char **err_str) override;
|
const char **err_str) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::io::usd
|
} // namespace blender::io::usd
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
#include "usd.h"
|
#include "usd.h"
|
||||||
#include "usd_reader_xform.h"
|
#include "usd_reader_xform.h"
|
||||||
|
|
||||||
|
struct GeometrySet;
|
||||||
struct Mesh;
|
struct Mesh;
|
||||||
|
|
||||||
namespace blender::io::usd {
|
namespace blender::io::usd {
|
||||||
@@ -19,10 +20,10 @@ class USDGeomReader : public USDXformReader {
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Mesh *read_mesh(struct Mesh *existing_mesh,
|
virtual void read_geometry(GeometrySet &geometry_set,
|
||||||
double motionSampleTime,
|
double motionSampleTime,
|
||||||
int read_flag,
|
int read_flag,
|
||||||
const char **err_str) = 0;
|
const char **err_str) = 0;
|
||||||
|
|
||||||
virtual bool topology_changed(Mesh * /* existing_mesh */, double /* motionSampleTime */)
|
virtual bool topology_changed(Mesh * /* existing_mesh */, double /* motionSampleTime */)
|
||||||
{
|
{
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
#include "usd_reader_material.h"
|
#include "usd_reader_material.h"
|
||||||
|
|
||||||
#include "BKE_customdata.h"
|
#include "BKE_customdata.h"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
#include "BKE_main.h"
|
#include "BKE_main.h"
|
||||||
#include "BKE_material.h"
|
#include "BKE_material.h"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
@@ -866,4 +867,17 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
|
|||||||
return active_mesh;
|
return active_mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void USDMeshReader::read_geometry(GeometrySet &geometry_set,
|
||||||
|
double motionSampleTime,
|
||||||
|
int read_flag,
|
||||||
|
const char **err_str)
|
||||||
|
{
|
||||||
|
Mesh *existing_mesh = geometry_set.get_mesh_for_write();
|
||||||
|
Mesh *new_mesh = read_mesh(existing_mesh, motionSampleTime, read_flag, err_str);
|
||||||
|
|
||||||
|
if (new_mesh != existing_mesh) {
|
||||||
|
geometry_set.replace_mesh(new_mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blender::io::usd
|
} // namespace blender::io::usd
|
||||||
|
@@ -48,10 +48,10 @@ class USDMeshReader : public USDGeomReader {
|
|||||||
void create_object(Main *bmain, double motionSampleTime) override;
|
void create_object(Main *bmain, double motionSampleTime) override;
|
||||||
void read_object_data(Main *bmain, double motionSampleTime) override;
|
void read_object_data(Main *bmain, double motionSampleTime) override;
|
||||||
|
|
||||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
void read_geometry(GeometrySet &geometry_set,
|
||||||
double motionSampleTime,
|
double motionSampleTime,
|
||||||
int read_flag,
|
int read_flag,
|
||||||
const char **err_str) override;
|
const char **err_str) override;
|
||||||
|
|
||||||
bool topology_changed(Mesh *existing_mesh, double motionSampleTime) override;
|
bool topology_changed(Mesh *existing_mesh, double motionSampleTime) override;
|
||||||
|
|
||||||
@@ -75,6 +75,11 @@ class USDMeshReader : public USDGeomReader {
|
|||||||
Mesh *mesh,
|
Mesh *mesh,
|
||||||
double motionSampleTime,
|
double motionSampleTime,
|
||||||
bool new_mesh);
|
bool new_mesh);
|
||||||
|
|
||||||
|
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||||
|
double motionSampleTime,
|
||||||
|
int read_flag,
|
||||||
|
const char **err_str);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::io::usd
|
} // namespace blender::io::usd
|
||||||
|
@@ -5,8 +5,10 @@
|
|||||||
#include "usd_reader_nurbs.h"
|
#include "usd_reader_nurbs.h"
|
||||||
|
|
||||||
#include "BKE_curve.h"
|
#include "BKE_curve.h"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
#include "BKE_object.h"
|
#include "BKE_object.h"
|
||||||
|
#include "BKE_spline.hh"
|
||||||
|
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
|
|
||||||
@@ -164,11 +166,35 @@ void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */,
|
static bool topology_changed(CurveEval *curve_eval, const pxr::VtIntArray &usdCounts)
|
||||||
const double motionSampleTime,
|
|
||||||
const int /* read_flag */,
|
|
||||||
const char ** /* err_str */)
|
|
||||||
{
|
{
|
||||||
|
if (!curve_eval) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curve_eval->splines().size() != usdCounts.size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int curve_idx = 0;
|
||||||
|
for (const SplinePtr &spline : curve_eval->splines()) {
|
||||||
|
const int num_in_usd = usdCounts[curve_idx++];
|
||||||
|
const int num_in_blender = spline->positions().size();
|
||||||
|
|
||||||
|
if (num_in_usd != num_in_blender) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USDNurbsReader::read_geometry(GeometrySet &geometry_set,
|
||||||
|
double motionSampleTime,
|
||||||
|
int /* read_flag */,
|
||||||
|
const char ** /* err_str */)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
pxr::UsdGeomCurves curve_prim_(prim_);
|
pxr::UsdGeomCurves curve_prim_(prim_);
|
||||||
|
|
||||||
pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
|
pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
|
||||||
@@ -178,62 +204,37 @@ Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */,
|
|||||||
pxr::VtIntArray usdCounts;
|
pxr::VtIntArray usdCounts;
|
||||||
|
|
||||||
vertexAttr.Get(&usdCounts, motionSampleTime);
|
vertexAttr.Get(&usdCounts, motionSampleTime);
|
||||||
int num_subcurves = usdCounts.size();
|
|
||||||
|
|
||||||
pxr::VtVec3fArray usdPoints;
|
pxr::VtVec3fArray usdPoints;
|
||||||
pointsAttr.Get(&usdPoints, motionSampleTime);
|
pointsAttr.Get(&usdPoints, motionSampleTime);
|
||||||
|
|
||||||
int vertex_idx = 0;
|
int vertex_idx = 0;
|
||||||
int curve_idx;
|
int curve_idx;
|
||||||
Curve *curve = static_cast<Curve *>(object_->data);
|
CurveEval *curve_eval = geometry_set.get_curve_for_write();
|
||||||
|
|
||||||
const int curve_count = BLI_listbase_count(&curve->nurb);
|
if (blender::io::usd::topology_changed(curve_eval, usdCounts)) {
|
||||||
bool same_topology = curve_count == num_subcurves;
|
Curve *curve = static_cast<Curve *>(object_->data);
|
||||||
|
|
||||||
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);
|
BKE_nurbList_free(&curve->nurb);
|
||||||
read_curve_sample(curve, motionSampleTime);
|
read_curve_sample(curve, motionSampleTime);
|
||||||
|
|
||||||
|
std::unique_ptr<CurveEval> new_curve_eval = curve_eval_from_dna_curve(*curve);
|
||||||
|
geometry_set.replace_curve(new_curve_eval.release(), GeometryOwnershipType::Editable);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
BLI_assert_msg(curve_eval, "curve_eval is null although the topology is the same !");
|
||||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
const int curve_count = curve_eval->splines().size();
|
||||||
const int totpoint = usdCounts[curve_idx];
|
for (curve_idx = 0; curve_idx < curve_count; curve_idx++) {
|
||||||
|
Spline *spline = curve_eval->splines()[curve_idx].get();
|
||||||
|
|
||||||
if (nurbs->bp) {
|
for (float3 &position : spline->positions()) {
|
||||||
BPoint *point = nurbs->bp;
|
position.x = usdPoints[vertex_idx][0];
|
||||||
|
position.y = usdPoints[vertex_idx][0];
|
||||||
for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
|
position.z = usdPoints[vertex_idx][0];
|
||||||
point->vec[0] = usdPoints[vertex_idx][0];
|
vertex_idx++;
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return BKE_mesh_new_nomain_from_curve(object_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blender::io::usd
|
} // namespace blender::io::usd
|
||||||
|
@@ -35,10 +35,10 @@ class USDNurbsReader : public USDGeomReader {
|
|||||||
|
|
||||||
void read_curve_sample(Curve *cu, double motionSampleTime);
|
void read_curve_sample(Curve *cu, double motionSampleTime);
|
||||||
|
|
||||||
Mesh *read_mesh(struct Mesh *existing_mesh,
|
void read_geometry(GeometrySet &geometry_set,
|
||||||
double motionSampleTime,
|
double motionSampleTime,
|
||||||
int read_flag,
|
int read_flag,
|
||||||
const char **err_str) override;
|
const char **err_str) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::io::usd
|
} // namespace blender::io::usd
|
||||||
|
@@ -12,6 +12,8 @@ extern "C" {
|
|||||||
struct CacheArchiveHandle;
|
struct CacheArchiveHandle;
|
||||||
struct CacheFile;
|
struct CacheFile;
|
||||||
struct CacheReader;
|
struct CacheReader;
|
||||||
|
struct GeometrySet;
|
||||||
|
struct Mesh;
|
||||||
struct Object;
|
struct Object;
|
||||||
struct bContext;
|
struct bContext;
|
||||||
|
|
||||||
@@ -90,13 +92,14 @@ void USD_free_handle(struct CacheArchiveHandle *handle);
|
|||||||
|
|
||||||
void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale);
|
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. */
|
#ifdef __cplusplus
|
||||||
struct Mesh *USD_read_mesh(struct CacheReader *reader,
|
void USD_read_geometry(CacheReader *reader,
|
||||||
struct Object *ob,
|
Object *ob,
|
||||||
struct Mesh *existing_mesh,
|
GeometrySet &geometry_set,
|
||||||
float time,
|
const float time,
|
||||||
const char **err_str,
|
const char **err_str,
|
||||||
int read_flag);
|
const int read_flag);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool USD_mesh_topology_changed(struct CacheReader *reader,
|
bool USD_mesh_topology_changed(struct CacheReader *reader,
|
||||||
struct Object *ob,
|
struct Object *ob,
|
||||||
|
@@ -55,6 +55,44 @@ typedef struct CacheFileLayer {
|
|||||||
int _pad;
|
int _pad;
|
||||||
} CacheFileLayer;
|
} CacheFileLayer;
|
||||||
|
|
||||||
|
/* CacheAttributeMapping::mapping */
|
||||||
|
enum {
|
||||||
|
/* Default mapping, so we do not make an arbitrary decision as to what is the default. Also used
|
||||||
|
* to mark the mapping as ignored. */
|
||||||
|
CACHEFILE_ATTRIBUTE_MAP_NONE,
|
||||||
|
CACHEFILE_ATTRIBUTE_MAP_TO_UVS,
|
||||||
|
CACHEFILE_ATTRIBUTE_MAP_TO_VERTEX_COLORS,
|
||||||
|
CACHEFILE_ATTRIBUTE_MAP_TO_WEIGHT_GROUPS,
|
||||||
|
CACHEFILE_ATTRIBUTE_MAP_TO_FLOAT2,
|
||||||
|
CACHEFILE_ATTRIBUTE_MAP_TO_FLOAT3,
|
||||||
|
CACHEFILE_ATTRIBUTE_MAP_TO_COLOR,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* CacheAttributeMapping::domain */
|
||||||
|
enum {
|
||||||
|
/* Try to automatically map the attribute to the right domain (default behavior without mapping.)
|
||||||
|
*/
|
||||||
|
CACHEFILE_ATTR_MAP_DOMAIN_AUTO,
|
||||||
|
CACHEFILE_ATTR_MAP_DOMAIN_POINT,
|
||||||
|
CACHEFILE_ATTR_MAP_DOMAIN_FACE_CORNER,
|
||||||
|
CACHEFILE_ATTR_MAP_DOMAIN_FACE,
|
||||||
|
CACHEFILE_ATTR_MAP_DOMAIN_CURVE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Custom data mapping for the attributes in the CacheFile. Since there might not be a standard way
|
||||||
|
* of expressing what an attribute should be (e.g. is this float2 attribute a UV map?), and since
|
||||||
|
* some software might write multi-dimensionnal data as arrays of 1D element (although the size of
|
||||||
|
* the array will be N-time its expected size were it written as N-D data), we delegate to the user
|
||||||
|
* the task of telling us what is supposed to be what through these mappings. */
|
||||||
|
typedef struct CacheAttributeMapping {
|
||||||
|
struct CacheAttributeMapping *next, *prev;
|
||||||
|
|
||||||
|
char name[64];
|
||||||
|
char mapping;
|
||||||
|
char domain;
|
||||||
|
char _pad[6];
|
||||||
|
} CacheAttributeMapping;
|
||||||
|
|
||||||
/* CacheFile::velocity_unit
|
/* CacheFile::velocity_unit
|
||||||
* Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */
|
* Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */
|
||||||
enum {
|
enum {
|
||||||
@@ -85,7 +123,8 @@ typedef struct CacheFile {
|
|||||||
/** The frame offset to subtract. */
|
/** The frame offset to subtract. */
|
||||||
float frame_offset;
|
float frame_offset;
|
||||||
|
|
||||||
char _pad[4];
|
/** Index of the currently selected attribute mapping in the UI, starts at 1 */
|
||||||
|
int active_attribute_mapping;
|
||||||
|
|
||||||
/** Animation flag. */
|
/** Animation flag. */
|
||||||
short flag;
|
short flag;
|
||||||
@@ -116,6 +155,8 @@ typedef struct CacheFile {
|
|||||||
/* Name of the velocity property in the archive. */
|
/* Name of the velocity property in the archive. */
|
||||||
char velocity_name[64];
|
char velocity_name[64];
|
||||||
|
|
||||||
|
ListBase attribute_mappings;
|
||||||
|
|
||||||
/* Runtime */
|
/* Runtime */
|
||||||
struct CacheArchiveHandle *handle;
|
struct CacheArchiveHandle *handle;
|
||||||
char handle_filepath[1024];
|
char handle_filepath[1024];
|
||||||
|
@@ -92,6 +92,7 @@ extern StructRNA RNA_ByteColorAttribute;
|
|||||||
extern StructRNA RNA_ByteColorAttributeValue;
|
extern StructRNA RNA_ByteColorAttributeValue;
|
||||||
extern StructRNA RNA_ByteIntAttribute;
|
extern StructRNA RNA_ByteIntAttribute;
|
||||||
extern StructRNA RNA_ByteIntAttributeValue;
|
extern StructRNA RNA_ByteIntAttributeValue;
|
||||||
|
extern StructRNA RNA_CacheAttributeMapping;
|
||||||
extern StructRNA RNA_CacheFile;
|
extern StructRNA RNA_CacheFile;
|
||||||
extern StructRNA RNA_CacheFileLayer;
|
extern StructRNA RNA_CacheFileLayer;
|
||||||
extern StructRNA RNA_Camera;
|
extern StructRNA RNA_Camera;
|
||||||
|
@@ -47,6 +47,16 @@ static void rna_CacheFileLayer_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
|
|||||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rna_CacheFile_attribute_mapping_update(Main *UNUSED(bmain),
|
||||||
|
Scene *UNUSED(scene),
|
||||||
|
PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||||
|
|
||||||
|
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
|
||||||
|
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void rna_CacheFile_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
static void rna_CacheFile_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
rna_CacheFile_update(bmain, scene, ptr);
|
rna_CacheFile_update(bmain, scene, ptr);
|
||||||
@@ -144,6 +154,87 @@ static void rna_CacheFile_layer_remove(CacheFile *cache_file, bContext *C, Point
|
|||||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CacheAttributeMapping *rna_CacheFile_attribute_mapping_new(CacheFile *cache_file,
|
||||||
|
bContext *C,
|
||||||
|
ReportList *reports,
|
||||||
|
const char *name,
|
||||||
|
const int mapping_type,
|
||||||
|
const int domain)
|
||||||
|
{
|
||||||
|
CacheAttributeMapping *mapping = BKE_cachefile_add_attribute_mapping(
|
||||||
|
cache_file, name, mapping_type, domain);
|
||||||
|
if (mapping == NULL) {
|
||||||
|
BKE_reportf(reports,
|
||||||
|
RPT_ERROR,
|
||||||
|
"Cannot add an attribute mapping to CacheFile '%s'",
|
||||||
|
cache_file->id.name + 2);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||||
|
BKE_cachefile_reload(depsgraph, cache_file);
|
||||||
|
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_CacheFile_attribute_mapping_remove(CacheFile *cache_file,
|
||||||
|
bContext *C,
|
||||||
|
PointerRNA *mapping_ptr)
|
||||||
|
{
|
||||||
|
CacheAttributeMapping *mapping = mapping_ptr->data;
|
||||||
|
BKE_cachefile_remove_attribute_mapping(cache_file, mapping);
|
||||||
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||||
|
BKE_cachefile_reload(depsgraph, cache_file);
|
||||||
|
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PointerRNA rna_CacheFile_active_attribute_mapping_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||||
|
return rna_pointer_inherit_refine(
|
||||||
|
ptr, &RNA_CacheAttributeMapping, BKE_cachefile_get_active_attribute_mapping(cache_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_CacheFile_active_attribute_mapping_set(PointerRNA *ptr,
|
||||||
|
PointerRNA value,
|
||||||
|
struct ReportList *reports)
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||||
|
int index = BLI_findindex(&cache_file->attribute_mappings, value.data);
|
||||||
|
if (index == -1) {
|
||||||
|
BKE_reportf(reports,
|
||||||
|
RPT_ERROR,
|
||||||
|
"Attribute mapping '%s' not found in object '%s'",
|
||||||
|
((CacheAttributeMapping *)value.data)->name,
|
||||||
|
cache_file->id.name + 2);
|
||||||
|
cache_file->active_attribute_mapping = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_file->active_attribute_mapping = index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rna_CacheFile_active_attribute_mapping_index_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||||
|
return cache_file->active_attribute_mapping - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_CacheFile_active_attribute_mapping_index_set(PointerRNA *ptr, int value)
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||||
|
cache_file->active_attribute_mapping = value + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_CacheFile_active_attribute_mapping_index_range(
|
||||||
|
PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||||
|
|
||||||
|
*min = 0;
|
||||||
|
*max = max_ii(0, BLI_listbase_count(&cache_file->attribute_mappings) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* cachefile.object_paths */
|
/* cachefile.object_paths */
|
||||||
@@ -163,6 +254,148 @@ static void rna_def_alembic_object_path(BlenderRNA *brna)
|
|||||||
RNA_define_lib_overridable(false);
|
RNA_define_lib_overridable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const EnumPropertyItem rna_enum_cache_attribute_mapping_items[] = {
|
||||||
|
{CACHEFILE_ATTRIBUTE_MAP_NONE, "MAP_NONE", 0, "None", ""},
|
||||||
|
{CACHEFILE_ATTRIBUTE_MAP_TO_UVS,
|
||||||
|
"MAP_TO_UVS",
|
||||||
|
0,
|
||||||
|
"UVs",
|
||||||
|
"Read the attribute as a UV map of the same name"},
|
||||||
|
{CACHEFILE_ATTRIBUTE_MAP_TO_VERTEX_COLORS,
|
||||||
|
"MAP_TO_VERTEX_COLORS",
|
||||||
|
0,
|
||||||
|
"Vertex Colors",
|
||||||
|
"Read the attribute as a vertex color layer of the same name"},
|
||||||
|
{CACHEFILE_ATTRIBUTE_MAP_TO_WEIGHT_GROUPS,
|
||||||
|
"MAP_TO_WEIGHT_GROUPS",
|
||||||
|
0,
|
||||||
|
"Weight Group",
|
||||||
|
"Read the attribute as a weight group channel of the same name"},
|
||||||
|
{CACHEFILE_ATTRIBUTE_MAP_TO_FLOAT2,
|
||||||
|
"MAP_TO_FLOAT2",
|
||||||
|
0,
|
||||||
|
"2D Vector",
|
||||||
|
"Interpret the attribute's data as generic 2D vectors"},
|
||||||
|
{CACHEFILE_ATTRIBUTE_MAP_TO_FLOAT3,
|
||||||
|
"MAP_TO_FLOAT3",
|
||||||
|
0,
|
||||||
|
"3D Vector",
|
||||||
|
"Interpret the attribute's data as generic 3D vectors"},
|
||||||
|
{CACHEFILE_ATTRIBUTE_MAP_TO_COLOR,
|
||||||
|
"MAP_TO_COLOR",
|
||||||
|
0,
|
||||||
|
"Color",
|
||||||
|
"Interpret the attribute's data as colors (RGBA)"},
|
||||||
|
{0, NULL, 0, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const EnumPropertyItem rna_enum_cache_attribute_domain_items[] = {
|
||||||
|
{CACHEFILE_ATTR_MAP_DOMAIN_AUTO,
|
||||||
|
"AUTO",
|
||||||
|
0,
|
||||||
|
"Automatic",
|
||||||
|
"Try to automatically determine the domain of the attribute"},
|
||||||
|
{CACHEFILE_ATTR_MAP_DOMAIN_POINT,
|
||||||
|
"POINT",
|
||||||
|
0,
|
||||||
|
"Point",
|
||||||
|
"The attribute is defined for each point"},
|
||||||
|
{CACHEFILE_ATTR_MAP_DOMAIN_FACE_CORNER,
|
||||||
|
"FACE_CORNER",
|
||||||
|
0,
|
||||||
|
"Face Corner",
|
||||||
|
"The attribute is defined for each face corner"},
|
||||||
|
{CACHEFILE_ATTR_MAP_DOMAIN_FACE, "FACE", 0, "Face", "The attribute is defined for each face"},
|
||||||
|
{CACHEFILE_ATTR_MAP_DOMAIN_CURVE,
|
||||||
|
"CURVE",
|
||||||
|
0,
|
||||||
|
"Curve",
|
||||||
|
"The attribute is defined for each curve"},
|
||||||
|
{0, NULL, 0, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rna_def_cachefile_attribute_mapping(BlenderRNA *brna)
|
||||||
|
{
|
||||||
|
StructRNA *srna = RNA_def_struct(brna, "CacheAttributeMapping", NULL);
|
||||||
|
RNA_def_struct_sdna(srna, "CacheAttributeMapping");
|
||||||
|
RNA_def_struct_ui_text(
|
||||||
|
srna,
|
||||||
|
"Cache Attribute Mapping",
|
||||||
|
"Attribute Mappin of the cache, used to define how to interpret certain attributes");
|
||||||
|
|
||||||
|
PropertyRNA *prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||||
|
RNA_def_property_ui_text(prop, "Name", "Name of the attribute to map");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_CacheFile_attribute_mapping_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, rna_enum_cache_attribute_mapping_items);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_CacheFile_attribute_mapping_update");
|
||||||
|
RNA_def_property_ui_text(prop, "Data Type", "Define the data type of the attribute");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, rna_enum_cache_attribute_domain_items);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_CacheFile_attribute_mapping_update");
|
||||||
|
RNA_def_property_ui_text(prop, "Domain", "Define the domain on which the attribute is written");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_def_cachefile_attribute_mappings(BlenderRNA *brna, PropertyRNA *cprop)
|
||||||
|
{
|
||||||
|
RNA_def_property_srna(cprop, "CacheAttributeMappings");
|
||||||
|
StructRNA *srna = RNA_def_struct(brna, "CacheAttributeMappings", NULL);
|
||||||
|
RNA_def_struct_sdna(srna, "CacheFile");
|
||||||
|
RNA_def_struct_ui_text(
|
||||||
|
srna, "Cache Attribute Mappings", "Collection of cache attribute mappings");
|
||||||
|
|
||||||
|
PropertyRNA *prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
|
||||||
|
RNA_def_property_struct_type(prop, "CacheAttributeMapping");
|
||||||
|
RNA_def_property_pointer_funcs(prop,
|
||||||
|
"rna_CacheFile_active_attribute_mapping_get",
|
||||||
|
"rna_CacheFile_active_attribute_mapping_set",
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Active Attribute Mapping", "Active attribute mapping of the CacheFile");
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Active Attribute Mapping Index", "Active index in attribute mappings array");
|
||||||
|
|
||||||
|
FunctionRNA *func;
|
||||||
|
PropertyRNA *parm;
|
||||||
|
|
||||||
|
/* Add a mapping. */
|
||||||
|
func = RNA_def_function(srna, "new", "rna_CacheFile_attribute_mapping_new");
|
||||||
|
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
|
||||||
|
RNA_def_function_ui_description(func, "Add a new attribute mapping");
|
||||||
|
/* Optional parameters. */
|
||||||
|
parm = RNA_def_string(func, "name", "Name", 64, "Name", "Name of the attribute to remap");
|
||||||
|
parm = RNA_def_enum(func,
|
||||||
|
"mapping_type",
|
||||||
|
rna_enum_cache_attribute_mapping_items,
|
||||||
|
CACHEFILE_ATTRIBUTE_MAP_NONE,
|
||||||
|
"Mapping Type",
|
||||||
|
"Type of the mapping");
|
||||||
|
parm = RNA_def_enum(func,
|
||||||
|
"domain",
|
||||||
|
rna_enum_cache_attribute_domain_items,
|
||||||
|
CACHEFILE_ATTR_MAP_DOMAIN_AUTO,
|
||||||
|
"Domain",
|
||||||
|
"Original domain of the attribute to remap");
|
||||||
|
/* Return type. */
|
||||||
|
parm = RNA_def_pointer(
|
||||||
|
func, "mapping", "CacheAttributeMapping", "", "Newly created attribute mapping");
|
||||||
|
RNA_def_function_return(func, parm);
|
||||||
|
|
||||||
|
/* Remove a mapping. */
|
||||||
|
func = RNA_def_function(srna, "remove", "rna_CacheFile_attribute_mapping_remove");
|
||||||
|
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||||
|
RNA_def_function_ui_description(func,
|
||||||
|
"Remove an existing attribute mapping from the cache file");
|
||||||
|
parm = RNA_def_pointer(
|
||||||
|
func, "mapping", "CacheAttributeMapping", "", "Attribute mapping to remove");
|
||||||
|
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||||
|
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* cachefile.object_paths */
|
/* cachefile.object_paths */
|
||||||
static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop)
|
static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop)
|
||||||
{
|
{
|
||||||
@@ -255,6 +488,18 @@ static void rna_def_cachefile(BlenderRNA *brna)
|
|||||||
"Alembic data themselves if possible");
|
"Alembic data themselves if possible");
|
||||||
RNA_def_property_update(prop, 0, "rna_CacheFile_dependency_update");
|
RNA_def_property_update(prop, 0, "rna_CacheFile_dependency_update");
|
||||||
|
|
||||||
|
static const EnumPropertyItem cache_file_type_items[] = {
|
||||||
|
{CACHE_FILE_TYPE_INVALID, "INVALID", 0, "Invalid", ""},
|
||||||
|
{CACHEFILE_TYPE_ALEMBIC, "ALEMBIC", 0, "Alembic", ""},
|
||||||
|
{CACHEFILE_TYPE_USD, "USD", 0, "USD", ""},
|
||||||
|
{0, NULL, 0, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, cache_file_type_items);
|
||||||
|
RNA_def_property_ui_text(prop, "Type", "Type of the file used for storing data");
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
|
||||||
/* ----------------- For Scene time ------------------- */
|
/* ----------------- For Scene time ------------------- */
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "override_frame", PROP_BOOLEAN, PROP_NONE);
|
prop = RNA_def_property(srna, "override_frame", PROP_BOOLEAN, PROP_NONE);
|
||||||
@@ -384,6 +629,23 @@ static void rna_def_cachefile(BlenderRNA *brna)
|
|||||||
"rna_CacheFile_active_layer_index_set",
|
"rna_CacheFile_active_layer_index_set",
|
||||||
"rna_CacheFile_active_layer_index_range");
|
"rna_CacheFile_active_layer_index_range");
|
||||||
|
|
||||||
|
/* ----------------- Attribute Mappings ----------------- */
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "attribute_mappings", PROP_COLLECTION, PROP_NONE);
|
||||||
|
RNA_def_property_collection_sdna(prop, NULL, "attribute_mappings", NULL);
|
||||||
|
RNA_def_property_struct_type(prop, "CacheAttributeMapping");
|
||||||
|
RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||||
|
RNA_def_property_ui_text(prop, "Cache Attribute Mappings", "Attribute mappings of the cache");
|
||||||
|
rna_def_cachefile_attribute_mappings(brna, prop);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "active_attribute_mapping_index", PROP_INT, PROP_UNSIGNED);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
|
RNA_def_property_int_sdna(prop, NULL, "active_attribute_mapping");
|
||||||
|
RNA_def_property_int_funcs(prop,
|
||||||
|
"rna_CacheFile_active_attribute_mapping_index_get",
|
||||||
|
"rna_CacheFile_active_attribute_mapping_index_set",
|
||||||
|
"rna_CacheFile_active_attribute_mapping_index_range");
|
||||||
|
|
||||||
RNA_define_lib_overridable(false);
|
RNA_define_lib_overridable(false);
|
||||||
|
|
||||||
rna_def_cachefile_object_paths(brna, prop);
|
rna_def_cachefile_object_paths(brna, prop);
|
||||||
@@ -396,6 +658,7 @@ void RNA_def_cachefile(BlenderRNA *brna)
|
|||||||
rna_def_cachefile(brna);
|
rna_def_cachefile(brna);
|
||||||
rna_def_alembic_object_path(brna);
|
rna_def_alembic_object_path(brna);
|
||||||
rna_def_cachefile_layer(brna);
|
rna_def_cachefile_layer(brna);
|
||||||
|
rna_def_cachefile_attribute_mapping(brna);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -59,7 +59,7 @@ set(SRC
|
|||||||
intern/MOD_meshcache_pc2.c
|
intern/MOD_meshcache_pc2.c
|
||||||
intern/MOD_meshcache_util.c
|
intern/MOD_meshcache_util.c
|
||||||
intern/MOD_meshdeform.c
|
intern/MOD_meshdeform.c
|
||||||
intern/MOD_meshsequencecache.c
|
intern/MOD_meshsequencecache.cc
|
||||||
intern/MOD_mirror.c
|
intern/MOD_mirror.c
|
||||||
intern/MOD_multires.c
|
intern/MOD_multires.c
|
||||||
intern/MOD_nodes.cc
|
intern/MOD_nodes.cc
|
||||||
|
@@ -25,11 +25,14 @@
|
|||||||
|
|
||||||
#include "BKE_cachefile.h"
|
#include "BKE_cachefile.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
|
#include "BKE_curve_to_mesh.hh"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
#include "BKE_lib_query.h"
|
#include "BKE_lib_query.h"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
#include "BKE_object.h"
|
#include "BKE_object.h"
|
||||||
#include "BKE_scene.h"
|
#include "BKE_scene.h"
|
||||||
#include "BKE_screen.h"
|
#include "BKE_screen.h"
|
||||||
|
#include "BKE_spline.hh"
|
||||||
|
|
||||||
#include "UI_interface.h"
|
#include "UI_interface.h"
|
||||||
#include "UI_resources.h"
|
#include "UI_resources.h"
|
||||||
@@ -79,7 +82,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
|
|||||||
|
|
||||||
BKE_modifier_copydata_generic(md, target, flag);
|
BKE_modifier_copydata_generic(md, target, flag);
|
||||||
|
|
||||||
tmcmd->reader = NULL;
|
tmcmd->reader = nullptr;
|
||||||
tmcmd->reader_object_path[0] = '\0';
|
tmcmd->reader_object_path[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +103,41 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
|
|||||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||||
|
|
||||||
/* leave it up to the modifier to check the file is valid on calculation */
|
/* leave it up to the modifier to check the file is valid on calculation */
|
||||||
return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
|
return (mcmd->cache_file == nullptr) || (mcmd->object_path[0] == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this invocation is for the ORCO mesh, and the mesh hasn't changed topology, we
|
||||||
|
* must return the mesh as-is instead of deforming it. */
|
||||||
|
static bool need_orco_mesh(MeshSeqCacheModifierData *mcmd,
|
||||||
|
const ModifierEvalContext *ctx,
|
||||||
|
Mesh *mesh,
|
||||||
|
float time,
|
||||||
|
const char **err_str)
|
||||||
|
{
|
||||||
|
CacheFile *cache_file = mcmd->cache_file;
|
||||||
|
|
||||||
|
if (ctx->flag & MOD_APPLY_ORCO) {
|
||||||
|
switch (cache_file->type) {
|
||||||
|
case CACHEFILE_TYPE_ALEMBIC:
|
||||||
|
#ifdef WITH_ALEMBIC
|
||||||
|
if (!ABC_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, err_str)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case CACHEFILE_TYPE_USD:
|
||||||
|
#ifdef WITH_USD
|
||||||
|
if (!USD_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, err_str)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case CACHE_FILE_TYPE_INVALID:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
|
static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
|
||||||
@@ -141,20 +178,103 @@ static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void modifyGeometry(ModifierData *md,
|
||||||
|
const ModifierEvalContext *ctx,
|
||||||
|
GeometrySet &geometry_set)
|
||||||
|
{
|
||||||
|
#ifdef WITH_ALEMBIC
|
||||||
|
MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
|
||||||
|
|
||||||
|
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
|
||||||
|
CacheFile *cache_file = mcmd->cache_file;
|
||||||
|
const float frame = DEG_get_ctime(ctx->depsgraph);
|
||||||
|
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
|
||||||
|
const char *err_str = nullptr;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
BKE_modifier_set_error(
|
||||||
|
ctx->object, md, "Could not create Alembic reader for file %s", cache_file->filepath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geometry_set.has_mesh()) {
|
||||||
|
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||||
|
if (need_orco_mesh(mcmd, ctx, mesh, time, &err_str)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do not process data if using a render procedural, return a box instead for displaying in the
|
||||||
|
* viewport. */
|
||||||
|
if (BKE_cache_file_uses_render_procedural(cache_file, scene, DEG_get_mode(ctx->depsgraph))) {
|
||||||
|
Mesh *org_mesh = nullptr;
|
||||||
|
if (geometry_set.has_mesh()) {
|
||||||
|
org_mesh = geometry_set.get_mesh_for_write();
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh *bbox = generate_bounding_box_mesh(ctx->object, org_mesh);
|
||||||
|
geometry_set = GeometrySet::create_with_mesh(bbox, GeometryOwnershipType::Editable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time (in frames or seconds) between two velocity samples. Automatically computed to
|
||||||
|
* scale the velocity vectors at render time for generating proper motion blur data. */
|
||||||
|
float velocity_scale = mcmd->velocity_scale;
|
||||||
|
if (mcmd->cache_file->velocity_unit == CACHEFILE_VELOCITY_UNIT_FRAME) {
|
||||||
|
velocity_scale *= FPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cache_file->type) {
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
# ifdef WITH_ALEMBIC
|
||||||
|
case CACHEFILE_TYPE_ALEMBIC: {
|
||||||
|
ABCReadParams params;
|
||||||
|
params.time = time;
|
||||||
|
params.read_flags = mcmd->read_flag;
|
||||||
|
params.velocity_name = mcmd->cache_file->velocity_name;
|
||||||
|
params.velocity_scale = velocity_scale;
|
||||||
|
params.mappings = &mcmd->cache_file->attribute_mappings;
|
||||||
|
ABC_read_geometry(mcmd->reader, ctx->object, geometry_set, ¶ms, &err_str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
# ifdef WITH_USD
|
||||||
|
case CACHEFILE_TYPE_USD: {
|
||||||
|
USD_read_geometry(mcmd->reader, ctx->object, geometry_set, time, &err_str, mcmd->read_flag);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err_str) {
|
||||||
|
BKE_modifier_set_error(ctx->object, md, "%s", err_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
UNUSED_VARS(ctx, md, geometry_set);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
|
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
|
||||||
{
|
{
|
||||||
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
|
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
|
||||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||||
|
|
||||||
/* Only used to check whether we are operating on org data or not... */
|
/* Only used to check whether we are operating on org data or not... */
|
||||||
Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL;
|
Mesh *me = (ctx->object->type == OB_MESH) ? static_cast<Mesh *>(ctx->object->data) : nullptr;
|
||||||
Mesh *org_mesh = mesh;
|
Mesh *org_mesh = mesh;
|
||||||
|
|
||||||
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
|
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
|
||||||
CacheFile *cache_file = mcmd->cache_file;
|
CacheFile *cache_file = mcmd->cache_file;
|
||||||
const float frame = DEG_get_ctime(ctx->depsgraph);
|
const float frame = DEG_get_ctime(ctx->depsgraph);
|
||||||
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
|
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
|
||||||
const char *err_str = NULL;
|
const char *err_str = nullptr;
|
||||||
|
|
||||||
if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
|
if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
|
||||||
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
|
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
|
||||||
@@ -172,30 +292,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||||||
return generate_bounding_box_mesh(ctx->object, org_mesh);
|
return generate_bounding_box_mesh(ctx->object, org_mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this invocation is for the ORCO mesh, and the mesh hasn't changed topology, we
|
if (need_orco_mesh(mcmd, ctx, mesh, time, &err_str)) {
|
||||||
* must return the mesh as-is instead of deforming it. */
|
return mesh;
|
||||||
if (ctx->flag & MOD_APPLY_ORCO) {
|
|
||||||
switch (cache_file->type) {
|
|
||||||
case CACHEFILE_TYPE_ALEMBIC:
|
|
||||||
# ifdef WITH_ALEMBIC
|
|
||||||
if (!ABC_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, &err_str)) {
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
break;
|
|
||||||
case CACHEFILE_TYPE_USD:
|
|
||||||
# ifdef WITH_USD
|
|
||||||
if (!USD_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, &err_str)) {
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
break;
|
|
||||||
case CACHE_FILE_TYPE_INVALID:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me != NULL) {
|
if (me != nullptr) {
|
||||||
MVert *mvert = mesh->mvert;
|
MVert *mvert = mesh->mvert;
|
||||||
MEdge *medge = mesh->medge;
|
MEdge *medge = mesh->medge;
|
||||||
MPoly *mpoly = mesh->mpoly;
|
MPoly *mpoly = mesh->mpoly;
|
||||||
@@ -204,53 +305,46 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||||||
* flags) and duplicate those too. */
|
* flags) and duplicate those too. */
|
||||||
if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
|
if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
|
||||||
/* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
|
/* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
|
||||||
mesh = (Mesh *)BKE_id_copy_ex(NULL,
|
mesh = (Mesh *)BKE_id_copy_ex(nullptr,
|
||||||
&mesh->id,
|
&mesh->id,
|
||||||
NULL,
|
nullptr,
|
||||||
LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
|
LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
|
||||||
LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW);
|
LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *result = NULL;
|
Mesh *result = nullptr;
|
||||||
|
|
||||||
switch (cache_file->type) {
|
GeometrySet geometry_set;
|
||||||
case CACHEFILE_TYPE_ALEMBIC: {
|
|
||||||
# ifdef WITH_ALEMBIC
|
|
||||||
/* Time (in frames or seconds) between two velocity samples. Automatically computed to
|
|
||||||
* scale the velocity vectors at render time for generating proper motion blur data. */
|
|
||||||
float velocity_scale = mcmd->velocity_scale;
|
|
||||||
if (mcmd->cache_file->velocity_unit == CACHEFILE_VELOCITY_UNIT_FRAME) {
|
|
||||||
velocity_scale *= FPS;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = ABC_read_mesh(mcmd->reader,
|
/* if (ctx->object->type == OB_CURVES_LEGACY) {
|
||||||
ctx->object,
|
std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve(
|
||||||
mesh,
|
*static_cast<Curve *>(ctx->object->data));
|
||||||
time,
|
geometry_set = GeometrySet::create_with_curve(curve_eval.release(),
|
||||||
&err_str,
|
GeometryOwnershipType::Editable);
|
||||||
mcmd->read_flag,
|
|
||||||
mcmd->cache_file->velocity_name,
|
|
||||||
velocity_scale);
|
|
||||||
# endif
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case CACHEFILE_TYPE_USD:
|
else */
|
||||||
# ifdef WITH_USD
|
{
|
||||||
result = USD_read_mesh(
|
geometry_set = GeometrySet::create_with_mesh(mesh, GeometryOwnershipType::Editable);
|
||||||
mcmd->reader, ctx->object, mesh, time * FPS, &err_str, mcmd->read_flag);
|
|
||||||
# endif
|
|
||||||
break;
|
|
||||||
case CACHE_FILE_TYPE_INVALID:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err_str) {
|
modifyGeometry(md, ctx, geometry_set);
|
||||||
BKE_modifier_set_error(ctx->object, md, "%s", err_str);
|
|
||||||
|
/* if (ctx->object->type == OB_CURVES_LEGACY) {
|
||||||
|
CurveEval *curve_eval = geometry_set.get_component_for_write<CurveComponent>().release();
|
||||||
|
|
||||||
|
if (curve_eval) {
|
||||||
|
result = blender::bke::curve_to_wire_mesh(*curve_eval);
|
||||||
|
delete curve_eval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else */
|
||||||
|
{
|
||||||
|
result = geometry_set.get_component_for_write<MeshComponent>().release();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) {
|
if (!ELEM(result, nullptr, mesh) && (mesh != org_mesh)) {
|
||||||
BKE_id_free(NULL, mesh);
|
BKE_id_free(nullptr, mesh);
|
||||||
mesh = org_mesh;
|
mesh = org_mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,6 +355,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void modifyGeometrySet(ModifierData *md,
|
||||||
|
const ModifierEvalContext *ctx,
|
||||||
|
GeometrySet *geometry_set)
|
||||||
|
{
|
||||||
|
modifyGeometry(md, ctx, *geometry_set);
|
||||||
|
}
|
||||||
|
|
||||||
static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mode)
|
static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mode)
|
||||||
{
|
{
|
||||||
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
|
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
|
||||||
@@ -285,7 +386,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
|
|||||||
{
|
{
|
||||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||||
|
|
||||||
if (mcmd->cache_file != NULL) {
|
if (mcmd->cache_file != nullptr) {
|
||||||
DEG_add_object_cache_relation(
|
DEG_add_object_cache_relation(
|
||||||
ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
|
ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
|
||||||
}
|
}
|
||||||
@@ -306,12 +407,13 @@ static void panel_draw(const bContext *C, Panel *panel)
|
|||||||
uiTemplateCacheFile(layout, C, ptr, "cache_file");
|
uiTemplateCacheFile(layout, C, ptr, "cache_file");
|
||||||
|
|
||||||
if (has_cache_file) {
|
if (has_cache_file) {
|
||||||
uiItemPointerR(layout, ptr, "object_path", &cache_file_ptr, "object_paths", NULL, ICON_NONE);
|
uiItemPointerR(
|
||||||
|
layout, ptr, "object_path", &cache_file_ptr, "object_paths", nullptr, ICON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RNA_enum_get(&ob_ptr, "type") == OB_MESH) {
|
if (RNA_enum_get(&ob_ptr, "type") == OB_MESH) {
|
||||||
uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
|
uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
|
||||||
uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE);
|
uiItemR(layout, ptr, "use_vertex_interpolation", 0, nullptr, ICON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
modifier_panel_end(layout, ptr);
|
modifier_panel_end(layout, ptr);
|
||||||
@@ -331,10 +433,42 @@ static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
|||||||
|
|
||||||
uiLayoutSetPropSep(layout, true);
|
uiLayoutSetPropSep(layout, true);
|
||||||
uiTemplateCacheFileVelocity(layout, &fileptr);
|
uiTemplateCacheFileVelocity(layout, &fileptr);
|
||||||
uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE);
|
uiItemR(layout, ptr, "velocity_scale", 0, nullptr, ICON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
static void attribute_remapping_panel_draw(const bContext *C, Panel *panel)
|
||||||
|
{
|
||||||
|
uiLayout *layout = panel->layout;
|
||||||
|
|
||||||
|
PointerRNA ob_ptr;
|
||||||
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||||
|
|
||||||
|
PointerRNA fileptr;
|
||||||
|
if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uiLayoutSetPropSep(layout, true);
|
||||||
|
uiTemplateCacheFileAttributeRemapping(layout, C, &fileptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void override_layers_panel_draw(const bContext *C, Panel *panel)
|
||||||
|
{
|
||||||
|
uiLayout *layout = panel->layout;
|
||||||
|
|
||||||
|
PointerRNA ob_ptr;
|
||||||
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||||
|
|
||||||
|
PointerRNA fileptr;
|
||||||
|
if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uiLayoutSetPropSep(layout, true);
|
||||||
|
uiTemplateCacheFileLayers(layout, C, &fileptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void time_settings_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||||
{
|
{
|
||||||
uiLayout *layout = panel->layout;
|
uiLayout *layout = panel->layout;
|
||||||
|
|
||||||
@@ -366,47 +500,42 @@ static void render_procedural_panel_draw(const bContext *C, Panel *panel)
|
|||||||
uiTemplateCacheFileProcedural(layout, C, &fileptr);
|
uiTemplateCacheFileProcedural(layout, C, &fileptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void override_layers_panel_draw(const bContext *C, Panel *panel)
|
|
||||||
{
|
|
||||||
uiLayout *layout = panel->layout;
|
|
||||||
|
|
||||||
PointerRNA ob_ptr;
|
|
||||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
|
||||||
|
|
||||||
PointerRNA fileptr;
|
|
||||||
if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uiLayoutSetPropSep(layout, true);
|
|
||||||
uiTemplateCacheFileLayers(layout, C, &fileptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void panelRegister(ARegionType *region_type)
|
static void panelRegister(ARegionType *region_type)
|
||||||
{
|
{
|
||||||
PanelType *panel_type = modifier_panel_register(
|
PanelType *panel_type = modifier_panel_register(
|
||||||
region_type, eModifierType_MeshSequenceCache, panel_draw);
|
region_type, eModifierType_MeshSequenceCache, panel_draw);
|
||||||
modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type);
|
modifier_subpanel_register(region_type,
|
||||||
|
"time_settings",
|
||||||
|
"Time Settings",
|
||||||
|
nullptr,
|
||||||
|
time_settings_panel_draw,
|
||||||
|
panel_type);
|
||||||
modifier_subpanel_register(region_type,
|
modifier_subpanel_register(region_type,
|
||||||
"render_procedural",
|
"render_procedural",
|
||||||
"Render Procedural",
|
"Render Procedural",
|
||||||
NULL,
|
nullptr,
|
||||||
render_procedural_panel_draw,
|
render_procedural_panel_draw,
|
||||||
panel_type);
|
panel_type);
|
||||||
modifier_subpanel_register(
|
|
||||||
region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type);
|
|
||||||
modifier_subpanel_register(region_type,
|
modifier_subpanel_register(region_type,
|
||||||
"override_layers",
|
"override_layers",
|
||||||
"Override Layers",
|
"Override Layers",
|
||||||
NULL,
|
nullptr,
|
||||||
override_layers_panel_draw,
|
override_layers_panel_draw,
|
||||||
panel_type);
|
panel_type);
|
||||||
|
modifier_subpanel_register(
|
||||||
|
region_type, "velocity", "Velocity", nullptr, velocity_panel_draw, panel_type);
|
||||||
|
modifier_subpanel_register(region_type,
|
||||||
|
"attribute_remapping",
|
||||||
|
"Attribute Remapping",
|
||||||
|
nullptr,
|
||||||
|
attribute_remapping_panel_draw,
|
||||||
|
panel_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
|
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
|
||||||
{
|
{
|
||||||
MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
|
MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
|
||||||
msmcd->reader = NULL;
|
msmcd->reader = nullptr;
|
||||||
msmcd->reader_object_path[0] = '\0';
|
msmcd->reader_object_path[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,29 +545,30 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
|
|||||||
/* structSize */ sizeof(MeshSeqCacheModifierData),
|
/* structSize */ sizeof(MeshSeqCacheModifierData),
|
||||||
/* srna */ &RNA_MeshSequenceCacheModifier,
|
/* srna */ &RNA_MeshSequenceCacheModifier,
|
||||||
/* type */ eModifierTypeType_Constructive,
|
/* type */ eModifierTypeType_Constructive,
|
||||||
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs,
|
/* flags */
|
||||||
|
static_cast<ModifierTypeFlag>(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs),
|
||||||
/* icon */ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */
|
/* icon */ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */
|
||||||
|
|
||||||
/* copyData */ copyData,
|
/* copyData */ copyData,
|
||||||
|
|
||||||
/* deformVerts */ NULL,
|
/* deformVerts */ nullptr,
|
||||||
/* deformMatrices */ NULL,
|
/* deformMatrices */ nullptr,
|
||||||
/* deformVertsEM */ NULL,
|
/* deformVertsEM */ nullptr,
|
||||||
/* deformMatricesEM */ NULL,
|
/* deformMatricesEM */ nullptr,
|
||||||
/* modifyMesh */ modifyMesh,
|
/* modifyMesh */ modifyMesh,
|
||||||
/* modifyGeometrySet */ NULL,
|
/* modifyGeometrySet */ modifyGeometrySet,
|
||||||
|
|
||||||
/* initData */ initData,
|
/* initData */ initData,
|
||||||
/* requiredDataMask */ NULL,
|
/* requiredDataMask */ nullptr,
|
||||||
/* freeData */ freeData,
|
/* freeData */ freeData,
|
||||||
/* isDisabled */ isDisabled,
|
/* isDisabled */ isDisabled,
|
||||||
/* updateDepsgraph */ updateDepsgraph,
|
/* updateDepsgraph */ updateDepsgraph,
|
||||||
/* dependsOnTime */ dependsOnTime,
|
/* dependsOnTime */ dependsOnTime,
|
||||||
/* dependsOnNormals */ NULL,
|
/* dependsOnNormals */ nullptr,
|
||||||
/* foreachIDLink */ foreachIDLink,
|
/* foreachIDLink */ foreachIDLink,
|
||||||
/* foreachTexLink */ NULL,
|
/* foreachTexLink */ nullptr,
|
||||||
/* freeRuntimeData */ NULL,
|
/* freeRuntimeData */ nullptr,
|
||||||
/* panelRegister */ panelRegister,
|
/* panelRegister */ panelRegister,
|
||||||
/* blendWrite */ NULL,
|
/* blendWrite */ nullptr,
|
||||||
/* blendRead */ blendRead,
|
/* blendRead */ blendRead,
|
||||||
};
|
};
|
Reference in New Issue
Block a user