Alembic: integrate cache file into the dependency graph
* The cache file datablock is now evaluated as part of the dependency graph, creating/freeing the Alembic file handle matching the current frame. Modifiers and constraints depend on this evaluation. * Cache file handles and readers now only exist on COW datablocks, never the original ones. * Object data paths are flushed back to the original for the user interface. * The cache file keeps a list of all readers associated with its handle, and automatically frees them when the handle is freed. This kind of sharing of data across datablocks is weak but we have no better mechanism for it. Fix T62720: Alembic sequences not working and crashing Differential Revision: https://developer.blender.org/D4774
This commit is contained in:
parent
a72a831570
commit
89826e0a0d
Notes:
blender-bot
2023-02-14 09:02:41 +01:00
Referenced by issue #62720, Importing Alembic Mesh Causes Blender To Crash As Well As Alembic Sequences/Playback of Alembic sequences does not work Referenced by issue #61710, Render crashes every 400 to 700 frames
|
@ -364,9 +364,6 @@ void AbcObjectReader::addCacheModifier()
|
|||
id_us_plus(&mcmd->cache_file->id);
|
||||
|
||||
BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
||||
|
||||
mcmd->reader = reinterpret_cast<CacheReader *>(this);
|
||||
this->incref();
|
||||
}
|
||||
|
||||
chrono_t AbcObjectReader::minTime() const
|
||||
|
|
|
@ -627,6 +627,7 @@ struct ImportJobData {
|
|||
char filename[1024];
|
||||
ImportSettings settings;
|
||||
|
||||
ArchiveReader *archive;
|
||||
std::vector<AbcObjectReader *> readers;
|
||||
|
||||
short *stop;
|
||||
|
@ -672,9 +673,9 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
|||
|
||||
cache_file->is_sequence = data->settings.is_sequence;
|
||||
cache_file->scale = data->settings.scale;
|
||||
cache_file->handle = handle_from_archive(archive);
|
||||
BLI_strncpy(cache_file->filepath, data->filename, 1024);
|
||||
STRNCPY(cache_file->filepath, data->filename);
|
||||
|
||||
data->archive = archive;
|
||||
data->settings.cache_file = cache_file;
|
||||
|
||||
*data->do_update = true;
|
||||
|
@ -855,6 +856,7 @@ static void import_endjob(void *user_data)
|
|||
static void import_freejob(void *user_data)
|
||||
{
|
||||
ImportJobData *data = static_cast<ImportJobData *>(user_data);
|
||||
delete data->archive;
|
||||
delete data;
|
||||
}
|
||||
|
||||
|
@ -886,6 +888,7 @@ bool ABC_import(bContext *C,
|
|||
job->settings.validate_meshes = validate_meshes;
|
||||
job->error_code = ABC_NO_ERROR;
|
||||
job->was_cancelled = false;
|
||||
job->archive = NULL;
|
||||
|
||||
G.is_break = false;
|
||||
|
||||
|
|
|
@ -29,8 +29,10 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct CacheFile;
|
||||
struct CacheReader;
|
||||
struct Depsgraph;
|
||||
struct Main;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
|
||||
void BKE_cachefiles_init(void);
|
||||
|
@ -52,24 +54,27 @@ void BKE_cachefile_make_local(struct Main *bmain,
|
|||
struct CacheFile *cache_file,
|
||||
const bool lib_local);
|
||||
|
||||
void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file);
|
||||
void BKE_cachefile_reload(struct Depsgraph *depsgraph, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_update_frame(struct Main *bmain,
|
||||
struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
const float ctime,
|
||||
const float fps);
|
||||
void BKE_cachefile_eval(struct Main *bmain,
|
||||
struct Depsgraph *depsgraph,
|
||||
struct CacheFile *cache_file);
|
||||
|
||||
bool BKE_cachefile_filepath_get(const struct Main *bmain,
|
||||
const struct Depsgraph *depsgrah,
|
||||
const struct CacheFile *cache_file,
|
||||
float frame,
|
||||
char r_filename[1024]);
|
||||
|
||||
float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
|
||||
float BKE_cachefile_time_offset(const struct CacheFile *cache_file,
|
||||
const float time,
|
||||
const float fps);
|
||||
|
||||
void BKE_cachefile_clean(struct Main *bmain, struct CacheFile *cache_file);
|
||||
/* Modifiers and constraints open and free readers through these. */
|
||||
void BKE_cachefile_reader_open(struct CacheFile *cache_file,
|
||||
struct CacheReader **reader,
|
||||
struct Object *object,
|
||||
const char *object_path);
|
||||
void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -21,18 +21,21 @@
|
|||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_cachefile.h"
|
||||
|
@ -41,10 +44,13 @@
|
|||
#include "BKE_modifier.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
# include "ABC_alembic.h"
|
||||
#endif
|
||||
|
||||
/* TODO: make this per cache file to avoid global locks. */
|
||||
static SpinLock spin;
|
||||
|
||||
void BKE_cachefiles_init(void)
|
||||
|
@ -57,6 +63,94 @@ void BKE_cachefiles_exit(void)
|
|||
BLI_spin_end(&spin);
|
||||
}
|
||||
|
||||
void BKE_cachefile_reader_open(CacheFile *cache_file,
|
||||
struct CacheReader **reader,
|
||||
Object *object,
|
||||
const char *object_path)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
|
||||
|
||||
if (cache_file->handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Open Alembic cache reader. */
|
||||
*reader = CacheReader_open_alembic_object(cache_file->handle, *reader, object, object_path);
|
||||
|
||||
/* Multiple modifiers and constraints can call this function concurrently. */
|
||||
BLI_spin_lock(&spin);
|
||||
if (*reader) {
|
||||
/* Register in set so we can free it when the cache file changes. */
|
||||
if (cache_file->handle_readers == NULL) {
|
||||
cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers");
|
||||
}
|
||||
BLI_gset_reinsert(cache_file->handle_readers, reader, NULL);
|
||||
}
|
||||
else if (cache_file->handle_readers) {
|
||||
/* Remove in case CacheReader_open_alembic_object free the existing reader. */
|
||||
BLI_gset_remove(cache_file->handle_readers, reader, NULL);
|
||||
}
|
||||
BLI_spin_unlock(&spin);
|
||||
#else
|
||||
UNUSED_VARS(reader, object, object_path);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BKE_cachefile_reader_free(CacheFile *cache_file, struct CacheReader **reader)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
|
||||
|
||||
if (*reader != NULL) {
|
||||
CacheReader_free(*reader);
|
||||
*reader = NULL;
|
||||
|
||||
/* Multiple modifiers and constraints can call this function concurrently. */
|
||||
BLI_spin_lock(&spin);
|
||||
if (cache_file->handle_readers) {
|
||||
BLI_gset_remove(cache_file->handle_readers, reader, NULL);
|
||||
}
|
||||
BLI_spin_unlock(&spin);
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(cache_file, reader);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cachefile_handle_free(CacheFile *cache_file)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
/* Free readers in all modifiers and constraints that use the handle, before
|
||||
* we free the handle itself. */
|
||||
BLI_spin_lock(&spin);
|
||||
if (cache_file->handle_readers) {
|
||||
GSetIterator gs_iter;
|
||||
GSET_ITER (gs_iter, cache_file->handle_readers) {
|
||||
struct CacheReader **reader = BLI_gsetIterator_getKey(&gs_iter);
|
||||
if (*reader != NULL) {
|
||||
CacheReader_free(*reader);
|
||||
*reader = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_gset_free(cache_file->handle_readers, NULL);
|
||||
cache_file->handle_readers = NULL;
|
||||
}
|
||||
BLI_spin_unlock(&spin);
|
||||
|
||||
/* Free handle. */
|
||||
if (cache_file->handle) {
|
||||
ABC_free_handle(cache_file->handle);
|
||||
cache_file->handle = NULL;
|
||||
}
|
||||
|
||||
cache_file->handle_filepath[0] = '\0';
|
||||
#else
|
||||
UNUSED_VARS(cache_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *BKE_cachefile_add(Main *bmain, const char *name)
|
||||
{
|
||||
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name, 0);
|
||||
|
@ -68,37 +162,23 @@ void *BKE_cachefile_add(Main *bmain, const char *name)
|
|||
|
||||
void BKE_cachefile_init(CacheFile *cache_file)
|
||||
{
|
||||
cache_file->handle = NULL;
|
||||
cache_file->filepath[0] = '\0';
|
||||
cache_file->override_frame = false;
|
||||
cache_file->frame = 0.0f;
|
||||
cache_file->is_sequence = false;
|
||||
cache_file->scale = 1.0f;
|
||||
cache_file->handle_mutex = BLI_mutex_alloc();
|
||||
BLI_listbase_clear(&cache_file->object_paths);
|
||||
|
||||
cache_file->handle = NULL;
|
||||
cache_file->handle_filepath[0] = '\0';
|
||||
cache_file->handle_readers = NULL;
|
||||
}
|
||||
|
||||
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
|
||||
void BKE_cachefile_free(CacheFile *cache_file)
|
||||
{
|
||||
BKE_animdata_free((ID *)cache_file, false);
|
||||
|
||||
if (cache_file->id.tag & LIB_TAG_NO_MAIN) {
|
||||
/* CoW/no-main copies reuse the existing ArchiveReader and mutex */
|
||||
return;
|
||||
}
|
||||
|
||||
if (cache_file->handle) {
|
||||
#ifdef WITH_ALEMBIC
|
||||
ABC_free_handle(cache_file->handle);
|
||||
#endif
|
||||
cache_file->handle = NULL;
|
||||
}
|
||||
if (cache_file->handle_mutex) {
|
||||
BLI_mutex_free(cache_file->handle_mutex);
|
||||
cache_file->handle_mutex = NULL;
|
||||
}
|
||||
|
||||
cachefile_handle_free(cache_file);
|
||||
BLI_freelistN(&cache_file->object_paths);
|
||||
}
|
||||
|
||||
|
@ -117,13 +197,8 @@ void BKE_cachefile_copy_data(Main *UNUSED(bmain),
|
|||
const CacheFile *UNUSED(cache_file_src),
|
||||
const int UNUSED(flag))
|
||||
{
|
||||
if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) {
|
||||
/* CoW/no-main copies reuse the existing ArchiveReader and mutex */
|
||||
return;
|
||||
}
|
||||
|
||||
cache_file_dst->handle = NULL;
|
||||
cache_file_dst->handle_mutex = NULL;
|
||||
cache_file_dst->handle_readers = NULL;
|
||||
BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths);
|
||||
}
|
||||
|
||||
|
@ -139,72 +214,51 @@ void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib
|
|||
BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
|
||||
}
|
||||
|
||||
void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
|
||||
void BKE_cachefile_reload(Depsgraph *depsgraph, CacheFile *cache_file)
|
||||
{
|
||||
/* To force reload, free the handle and tag depsgraph to load it again. */
|
||||
CacheFile *cache_file_eval = (CacheFile *)DEG_get_evaluated_id(depsgraph, &cache_file->id);
|
||||
if (cache_file_eval) {
|
||||
cachefile_handle_free(cache_file_eval);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
|
||||
}
|
||||
|
||||
void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file)
|
||||
{
|
||||
BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
|
||||
|
||||
/* Compute filepath. */
|
||||
char filepath[FILE_MAX];
|
||||
|
||||
BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
|
||||
BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
if (cache_file->handle) {
|
||||
ABC_free_handle(cache_file->handle);
|
||||
if (!BKE_cachefile_filepath_get(bmain, depsgraph, cache_file, filepath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test if filepath change or if we can keep the existing handle. */
|
||||
if (STREQ(cache_file->handle_filepath, filepath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cachefile_handle_free(cache_file);
|
||||
BLI_freelistN(&cache_file->object_paths);
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
|
||||
BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
|
||||
{
|
||||
BLI_spin_lock(&spin);
|
||||
if (cache_file->handle_mutex == NULL) {
|
||||
cache_file->handle_mutex = BLI_mutex_alloc();
|
||||
}
|
||||
BLI_spin_unlock(&spin);
|
||||
|
||||
BLI_mutex_lock(cache_file->handle_mutex);
|
||||
|
||||
if (cache_file->handle == NULL) {
|
||||
/* Assigning to a CoW copy is a bad idea; assign to the original instead. */
|
||||
BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
|
||||
BKE_cachefile_reload(bmain, cache_file);
|
||||
}
|
||||
|
||||
BLI_mutex_unlock(cache_file->handle_mutex);
|
||||
}
|
||||
|
||||
void BKE_cachefile_update_frame(
|
||||
Main *bmain, struct Depsgraph *depsgraph, Scene *scene, const float ctime, const float fps)
|
||||
{
|
||||
CacheFile *cache_file;
|
||||
char filename[FILE_MAX];
|
||||
|
||||
for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
|
||||
/* TODO: dependency graph should be updated to do drivers on cachefile.
|
||||
* Execute drivers only, as animation has already been done. */
|
||||
BKE_animsys_evaluate_animdata(
|
||||
depsgraph, scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
|
||||
|
||||
if (!cache_file->is_sequence) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
|
||||
|
||||
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
|
||||
BKE_cachefile_clean(bmain, cache_file);
|
||||
#ifdef WITH_ALEMBIC
|
||||
ABC_free_handle(cache_file->handle);
|
||||
cache_file->handle = ABC_create_handle(filename, NULL);
|
||||
#endif
|
||||
}
|
||||
if (DEG_is_active(depsgraph)) {
|
||||
/* Flush object paths back to original datablock for UI. */
|
||||
CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id);
|
||||
BLI_freelistN(&cache_file_orig->object_paths);
|
||||
BLI_duplicatelist(&cache_file_orig->object_paths, &cache_file->object_paths);
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_cachefile_filepath_get(const Main *bmain,
|
||||
const Depsgraph *depsgraph,
|
||||
const CacheFile *cache_file,
|
||||
float frame,
|
||||
char r_filepath[FILE_MAX])
|
||||
{
|
||||
BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
|
||||
|
@ -214,6 +268,11 @@ bool BKE_cachefile_filepath_get(const Main *bmain,
|
|||
int frame_len;
|
||||
|
||||
if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
|
||||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||
const float ctime = BKE_scene_frame_get(scene);
|
||||
const float fps = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
|
||||
const float frame = BKE_cachefile_time_offset(cache_file, ctime, fps);
|
||||
|
||||
char ext[32];
|
||||
BLI_path_frame_strip(r_filepath, ext);
|
||||
BLI_path_frame(r_filepath, frame, frame_len);
|
||||
|
@ -226,47 +285,9 @@ bool BKE_cachefile_filepath_get(const Main *bmain,
|
|||
return true;
|
||||
}
|
||||
|
||||
float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps)
|
||||
float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, const float fps)
|
||||
{
|
||||
const float time_offset = cache_file->frame_offset / fps;
|
||||
const float frame = (cache_file->override_frame ? cache_file->frame : time);
|
||||
return cache_file->is_sequence ? frame : frame / fps - time_offset;
|
||||
}
|
||||
|
||||
/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
|
||||
void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file)
|
||||
{
|
||||
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
|
||||
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
|
||||
|
||||
if (md) {
|
||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||
|
||||
if (cache_file == mcmd->cache_file) {
|
||||
#ifdef WITH_ALEMBIC
|
||||
if (mcmd->reader != NULL) {
|
||||
CacheReader_free(mcmd->reader);
|
||||
}
|
||||
#endif
|
||||
mcmd->reader = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (bConstraint *con = ob->constraints.first; con; con = con->next) {
|
||||
if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
|
||||
if (cache_file == data->cache_file) {
|
||||
#ifdef WITH_ALEMBIC
|
||||
if (data->reader != NULL) {
|
||||
CacheReader_free(data->reader);
|
||||
}
|
||||
#endif
|
||||
data->reader = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4835,13 +4835,9 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
|
|||
const float frame = DEG_get_ctime(cob->depsgraph);
|
||||
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
|
||||
|
||||
/* Must always load ABC handle on original. */
|
||||
CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id);
|
||||
BKE_cachefile_ensure_handle(G.main, cache_file_orig);
|
||||
|
||||
if (!data->reader) {
|
||||
data->reader = CacheReader_open_alembic_object(
|
||||
cache_file_orig->handle, data->reader, cob->ob, data->object_path);
|
||||
if (!data->reader || !STREQ(data->reader_object_path, data->object_path)) {
|
||||
STRNCPY(data->reader_object_path, data->object_path);
|
||||
BKE_cachefile_reader_open(cache_file, &data->reader, cob->ob, data->object_path);
|
||||
}
|
||||
|
||||
ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
|
||||
|
@ -4859,12 +4855,8 @@ static void transformcache_copy(bConstraint *con, bConstraint *srccon)
|
|||
|
||||
BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
|
||||
dst->cache_file = src->cache_file;
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
if (dst->reader) {
|
||||
CacheReader_incref(dst->reader);
|
||||
}
|
||||
#endif
|
||||
dst->reader = NULL;
|
||||
dst->reader_object_path[0] = '\0';
|
||||
}
|
||||
|
||||
static void transformcache_free(bConstraint *con)
|
||||
|
@ -4872,10 +4864,8 @@ static void transformcache_free(bConstraint *con)
|
|||
bTransformCacheConstraint *data = con->data;
|
||||
|
||||
if (data->reader) {
|
||||
#ifdef WITH_ALEMBIC
|
||||
CacheReader_free(data->reader);
|
||||
#endif
|
||||
data->reader = NULL;
|
||||
BKE_cachefile_reader_free(data->cache_file, &data->reader);
|
||||
data->reader_object_path[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1565,15 +1565,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
|
|||
BKE_image_editors_update_frame(bmain, scene->r.cfra);
|
||||
BKE_sound_set_cfra(scene->r.cfra);
|
||||
DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
|
||||
/* Update animated cache files for modifiers.
|
||||
*
|
||||
* TODO(sergey): Make this a depsgraph node?
|
||||
*/
|
||||
BKE_cachefile_update_frame(bmain,
|
||||
depsgraph,
|
||||
scene,
|
||||
ctime,
|
||||
(((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base));
|
||||
#ifdef POSE_ANIMATION_WORKAROUND
|
||||
scene_armature_depsgraph_workaround(bmain, depsgraph);
|
||||
#endif
|
||||
|
|
|
@ -3305,7 +3305,8 @@ static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
|
|||
{
|
||||
BLI_listbase_clear(&cache_file->object_paths);
|
||||
cache_file->handle = NULL;
|
||||
cache_file->handle_mutex = NULL;
|
||||
cache_file->handle_filepath[0] = '\0';
|
||||
cache_file->handle_readers = NULL;
|
||||
|
||||
/* relink animdata */
|
||||
cache_file->adt = newdataadr(fd, cache_file->adt);
|
||||
|
@ -3739,6 +3740,7 @@ static void direct_link_constraints(FileData *fd, ListBase *lb)
|
|||
case CONSTRAINT_TYPE_TRANSFORM_CACHE: {
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
data->reader = NULL;
|
||||
data->reader_object_path[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5745,6 +5747,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
|
|||
else if (md->type == eModifierType_MeshSequenceCache) {
|
||||
MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
|
||||
msmcd->reader = NULL;
|
||||
msmcd->reader_object_path[0] = '\0';
|
||||
}
|
||||
else if (md->type == eModifierType_SurfaceDeform) {
|
||||
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
|
||||
|
|
|
@ -65,6 +65,7 @@ extern "C" {
|
|||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_curve.h"
|
||||
|
@ -1469,11 +1470,16 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
|
|||
return;
|
||||
}
|
||||
ID *cache_file_id = &cache_file->id;
|
||||
add_id_node(cache_file_id);
|
||||
CacheFile *cache_file_cow = get_cow_datablock(cache_file);
|
||||
/* Animation, */
|
||||
build_animdata(cache_file_id);
|
||||
build_parameters(cache_file_id);
|
||||
/* Cache evaluation itself. */
|
||||
add_operation_node(cache_file_id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE);
|
||||
add_operation_node(cache_file_id,
|
||||
NodeType::CACHE,
|
||||
OperationCode::FILE_CACHE_UPDATE,
|
||||
function_bind(BKE_cachefile_eval, bmain_, _1, cache_file_cow));
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_mask(Mask *mask)
|
||||
|
|
|
@ -2222,6 +2222,14 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
|
|||
ComponentKey datablock_key(&cache_file->id, NodeType::CACHE);
|
||||
add_relation(animation_key, datablock_key, "Datablock Animation");
|
||||
}
|
||||
|
||||
/* Cache file updates */
|
||||
if (cache_file->is_sequence) {
|
||||
OperationKey cache_update_key(
|
||||
&cache_file->id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE);
|
||||
TimeSourceKey time_src_key;
|
||||
add_relation(time_src_key, cache_update_key, "TimeSrc -> Cache File Eval");
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_mask(Mask *mask)
|
||||
|
@ -2329,7 +2337,8 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
|
|||
continue;
|
||||
}
|
||||
int rel_flag = (RELATION_FLAG_NO_FLUSH | RELATION_FLAG_GODMODE);
|
||||
if (id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) {
|
||||
if ((id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) ||
|
||||
(id_type == ID_CF && comp_node->type == NodeType::CACHE)) {
|
||||
rel_flag &= ~RELATION_FLAG_NO_FLUSH;
|
||||
}
|
||||
/* Notes on exceptions:
|
||||
|
|
|
@ -6711,17 +6711,18 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
|
|||
uiItemR(row, &fileptr, "override_frame", 0, "Override Frame", ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiLayoutSetEnabled(row, RNA_boolean_get(&fileptr, "override_frame"));
|
||||
uiLayoutSetActive(row, RNA_boolean_get(&fileptr, "override_frame"));
|
||||
uiItemR(row, &fileptr, "frame", 0, "Frame", ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, &fileptr, "frame_offset", 0, "Frame Offset", ICON_NONE);
|
||||
uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence"));
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiLayoutSetEnabled(row, (sbuts->mainb == BCONTEXT_CONSTRAINT));
|
||||
uiLayoutSetActive(row, (sbuts->mainb == BCONTEXT_CONSTRAINT));
|
||||
uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE);
|
||||
|
||||
/* TODO: unused for now, so no need to expose. */
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
@ -93,7 +95,7 @@ static int cachefile_open_exec(bContext *C, wmOperator *op)
|
|||
|
||||
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename), 0);
|
||||
BLI_strncpy(cache_file->filepath, filename, FILE_MAX);
|
||||
BKE_cachefile_reload(bmain, cache_file);
|
||||
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
|
||||
|
||||
/* Will be set when running invoke, not exec directly. */
|
||||
if (op->customdata != NULL) {
|
||||
|
@ -137,7 +139,7 @@ void CACHEFILE_OT_open(wmOperatorType *ot)
|
|||
|
||||
/* ***************************** Reload Operator **************************** */
|
||||
|
||||
static int cachefile_reload_exec(bContext *C, wmOperator *op)
|
||||
static int cachefile_reload_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||
|
||||
|
@ -145,14 +147,10 @@ static int cachefile_reload_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
BLI_freelistN(&cache_file->object_paths);
|
||||
BKE_cachefile_reload(bmain, cache_file);
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph(C);
|
||||
BKE_cachefile_reload(depsgraph, cache_file);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
||||
UNUSED_VARS(op);
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_reload(wmOperatorType *ot)
|
||||
|
|
|
@ -30,10 +30,12 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct GSet;
|
||||
|
||||
/* CacheFile::flag */
|
||||
enum {
|
||||
CACHEFILE_DS_EXPAND = (1 << 0),
|
||||
CACHEFILE_DIRTY = (1 << 1),
|
||||
CACHEFILE_UNUSED_0 = (1 << 1),
|
||||
};
|
||||
|
||||
/* CacheFile::draw_flag */
|
||||
|
@ -53,9 +55,6 @@ typedef struct CacheFile {
|
|||
ID id;
|
||||
struct AnimData *adt;
|
||||
|
||||
struct AbcArchiveHandle *handle;
|
||||
void *handle_mutex;
|
||||
|
||||
/** Paths of the objects inside of the Alembic archive referenced by this CacheFile. */
|
||||
ListBase object_paths;
|
||||
|
||||
|
@ -78,6 +77,11 @@ typedef struct CacheFile {
|
|||
short draw_flag;
|
||||
|
||||
char _pad[4];
|
||||
|
||||
/* Runtime */
|
||||
struct AbcArchiveHandle *handle;
|
||||
char handle_filepath[1024];
|
||||
struct GSet *handle_readers;
|
||||
} CacheFile;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -593,9 +593,12 @@ typedef struct bObjectSolverConstraint {
|
|||
/* Transform matrix cache constraint */
|
||||
typedef struct bTransformCacheConstraint {
|
||||
struct CacheFile *cache_file;
|
||||
struct CacheReader *reader;
|
||||
/** FILE_MAX. */
|
||||
char object_path[1024];
|
||||
|
||||
/* Runtime. */
|
||||
struct CacheReader *reader;
|
||||
char reader_object_path[1024];
|
||||
} bTransformCacheConstraint;
|
||||
|
||||
/* ------------------------------------------ */
|
||||
|
|
|
@ -1852,12 +1852,15 @@ typedef struct MeshSeqCacheModifierData {
|
|||
ModifierData modifier;
|
||||
|
||||
struct CacheFile *cache_file;
|
||||
struct CacheReader *reader;
|
||||
/** 1024 = FILE_MAX. */
|
||||
char object_path[1024];
|
||||
|
||||
char read_flag;
|
||||
char _pad[7];
|
||||
|
||||
/* Runtime. */
|
||||
struct CacheReader *reader;
|
||||
char reader_object_path[1024];
|
||||
} MeshSeqCacheModifierData;
|
||||
|
||||
/* MeshSeqCacheModifierData.read_flag */
|
||||
|
|
|
@ -45,29 +45,12 @@
|
|||
# include "../../../alembic/ABC_alembic.h"
|
||||
# endif
|
||||
|
||||
static void rna_CacheFile_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
static void rna_CacheFile_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)ptr->data;
|
||||
|
||||
DEG_id_tag_update(&cache_file->id, 0);
|
||||
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||
|
||||
UNUSED_VARS(bmain, scene);
|
||||
}
|
||||
|
||||
static void rna_CacheFile_update_handle(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
CacheFile *cache_file = ptr->data;
|
||||
|
||||
if ((cache_file->flag & CACHEFILE_DIRTY) != 0) {
|
||||
BKE_cachefile_clean(bmain, cache_file);
|
||||
BLI_freelistN(&cache_file->object_paths);
|
||||
cache_file->flag &= ~CACHEFILE_DIRTY;
|
||||
}
|
||||
|
||||
BKE_cachefile_reload(bmain, cache_file);
|
||||
|
||||
rna_CacheFile_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||
|
@ -76,20 +59,6 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P
|
|||
rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL);
|
||||
}
|
||||
|
||||
static void rna_CacheFile_filename_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
CacheFile *cache_file = ptr->data;
|
||||
|
||||
if (STREQ(cache_file->filepath, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Different file is opened, close all readers. */
|
||||
cache_file->flag |= CACHEFILE_DIRTY;
|
||||
|
||||
BLI_strncpy(cache_file->filepath, value, sizeof(cache_file->filepath));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* cachefile.object_paths */
|
||||
|
@ -122,9 +91,8 @@ static void rna_def_cachefile(BlenderRNA *brna)
|
|||
RNA_def_struct_ui_icon(srna, ICON_FILE);
|
||||
|
||||
PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
|
||||
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CacheFile_filename_set");
|
||||
RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file");
|
||||
RNA_def_property_update(prop, 0, "rna_CacheFile_update_handle");
|
||||
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
|
||||
|
||||
prop = RNA_def_property(srna, "is_sequence", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_ui_text(
|
||||
|
|
|
@ -729,22 +729,6 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v
|
|||
}
|
||||
}
|
||||
|
||||
static void rna_Constraint_transformCache_object_path_update(Main *bmain,
|
||||
Scene *scene,
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_ALEMBIC
|
||||
bConstraint *con = (bConstraint *)ptr->data;
|
||||
bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
|
||||
Object *ob = (Object *)ptr->id.data;
|
||||
|
||||
data->reader = CacheReader_open_alembic_object(
|
||||
data->cache_file->handle, data->reader, ob, data->object_path);
|
||||
# endif
|
||||
|
||||
rna_Constraint_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static const EnumPropertyItem constraint_distance_items[] = {
|
||||
|
@ -2902,7 +2886,7 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
|
|||
prop,
|
||||
"Object Path",
|
||||
"Path to the object in the Alembic archive used to lookup the transform matrix");
|
||||
RNA_def_property_update(prop, 0, "rna_Constraint_transformCache_object_path_update");
|
||||
RNA_def_property_update(prop, 0, "rna_Constraint_update");
|
||||
}
|
||||
|
||||
/* base struct for constraints */
|
||||
|
|
|
@ -1300,19 +1300,6 @@ static bool rna_SurfaceDeformModifier_is_bound_get(PointerRNA *ptr)
|
|||
return (((SurfaceDeformModifierData *)ptr->data)->verts != NULL);
|
||||
}
|
||||
|
||||
static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_ALEMBIC
|
||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data;
|
||||
Object *ob = (Object *)ptr->id.data;
|
||||
|
||||
mcmd->reader = CacheReader_open_alembic_object(
|
||||
mcmd->cache_file->handle, mcmd->reader, ob, mcmd->object_path);
|
||||
# endif
|
||||
|
||||
rna_Modifier_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static bool rna_ParticleInstanceModifier_particle_system_poll(PointerRNA *ptr,
|
||||
const PointerRNA value)
|
||||
{
|
||||
|
@ -5107,7 +5094,7 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
|
|||
prop,
|
||||
"Object Path",
|
||||
"Path to the object in the Alembic archive used to lookup geometric data");
|
||||
RNA_def_property_update(prop, 0, "rna_MeshSequenceCache_object_path_update");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
static const EnumPropertyItem read_flag_items[] = {
|
||||
{MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""},
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
* \ingroup modifiers
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
@ -47,6 +52,9 @@ static void initData(ModifierData *md)
|
|||
mcmd->cache_file = NULL;
|
||||
mcmd->object_path[0] = '\0';
|
||||
mcmd->read_flag = MOD_MESHSEQ_READ_ALL;
|
||||
|
||||
mcmd->reader = NULL;
|
||||
mcmd->reader_object_path[0] = '\0';
|
||||
}
|
||||
|
||||
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
|
||||
|
@ -59,6 +67,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
|
|||
modifier_copyData_generic(md, target, flag);
|
||||
|
||||
tmcmd->reader = NULL;
|
||||
tmcmd->reader_object_path[0] = '\0';
|
||||
}
|
||||
|
||||
static void freeData(ModifierData *md)
|
||||
|
@ -66,10 +75,8 @@ static void freeData(ModifierData *md)
|
|||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||
|
||||
if (mcmd->reader) {
|
||||
#ifdef WITH_ALEMBIC
|
||||
CacheReader_free(mcmd->reader);
|
||||
#endif
|
||||
mcmd->reader = NULL;
|
||||
mcmd->reader_object_path[0] = '\0';
|
||||
BKE_cachefile_reader_free(mcmd->cache_file, &mcmd->reader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,17 +100,14 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
|
|||
Mesh *org_mesh = mesh;
|
||||
|
||||
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(mcmd->cache_file, frame, FPS);
|
||||
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
|
||||
const char *err_str = NULL;
|
||||
|
||||
CacheFile *cache_file = (CacheFile *)DEG_get_original_id(&mcmd->cache_file->id);
|
||||
|
||||
BKE_cachefile_ensure_handle(G.main, cache_file);
|
||||
|
||||
if (!mcmd->reader) {
|
||||
mcmd->reader = CacheReader_open_alembic_object(
|
||||
cache_file->handle, NULL, ctx->object, mcmd->object_path);
|
||||
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) {
|
||||
modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath);
|
||||
return mesh;
|
||||
|
|
Loading…
Reference in New Issue