diff options
Diffstat (limited to 'source')
18 files changed, 607 insertions, 9 deletions
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index 0ab814c2d94..c6821d88d2a 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -28,6 +28,7 @@ extern "C" { #endif struct CacheFile; +struct CacheFileLayer; struct CacheReader; struct Depsgraph; struct Main; @@ -69,6 +70,15 @@ bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file, struct Scene *scene, int dag_eval_mode); +/* Add a layer to the cache_file. Return NULL if the filename is already that of an existing layer + * or if the number of layers exceeds the maximum allowed layer count. */ +struct CacheFileLayer *BKE_cachefile_add_layer(struct CacheFile *cache_file, + const char filename[1024]); + +struct CacheFileLayer *BKE_cachefile_get_active_layer(struct CacheFile *cache_file); + +void BKE_cachefile_remove_layer(struct CacheFile *cache_file, struct CacheFileLayer *layer); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 8833f3eabe9..75df2e98fcd 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -54,6 +54,8 @@ #include "BLO_read_write.h" +#include "MEM_guardedalloc.h" + #ifdef WITH_ALEMBIC # include "ABC_alembic.h" #endif @@ -86,6 +88,7 @@ static void cache_file_copy_data(Main *UNUSED(bmain), cache_file_dst->handle = NULL; cache_file_dst->handle_readers = NULL; BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths); + BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers); } static void cache_file_free_data(ID *id) @@ -93,6 +96,7 @@ static void cache_file_free_data(ID *id) CacheFile *cache_file = (CacheFile *)id; cachefile_handle_free(cache_file); BLI_freelistN(&cache_file->object_paths); + BLI_freelistN(&cache_file->layers); } static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data) @@ -117,6 +121,11 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a if (cache_file->adt) { BKE_animdata_blend_write(writer, cache_file->adt); } + + /* write layers */ + LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) { + BLO_write_struct(writer, CacheFileLayer, layer); + } } static void cache_file_blend_read_data(BlendDataReader *reader, ID *id) @@ -130,6 +139,9 @@ static void cache_file_blend_read_data(BlendDataReader *reader, ID *id) /* relink animdata */ BLO_read_data_address(reader, &cache_file->adt); BKE_animdata_blend_read_data(reader, cache_file->adt); + + /* relink layers */ + BLO_read_list(reader, &cache_file->layers); } IDTypeInfo IDType_ID_CF = { @@ -364,7 +376,8 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file #ifdef WITH_ALEMBIC if (BLI_path_extension_check_glob(filepath, "*abc")) { cache_file->type = CACHEFILE_TYPE_ALEMBIC; - cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths); + cache_file->handle = ABC_create_handle( + bmain, filepath, cache_file->layers.first, &cache_file->object_paths); BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX); } #endif @@ -435,3 +448,35 @@ bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file, const bool is_final_render = (eEvaluationMode)dag_eval_mode == DAG_EVAL_RENDER; return cache_file->use_render_procedural && !is_final_render; } + +CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filename[1024]) +{ + for (CacheFileLayer *layer = cache_file->layers.first; layer; layer = layer->next) { + if (STREQ(layer->filepath, filename)) { + return NULL; + } + } + + const int num_layers = BLI_listbase_count(&cache_file->layers); + + CacheFileLayer *layer = MEM_callocN(sizeof(CacheFileLayer), "CacheFileLayer"); + BLI_strncpy(layer->filepath, filename, sizeof(layer->filepath)); + + BLI_addtail(&cache_file->layers, layer); + + cache_file->active_layer = (char)(num_layers + 1); + + return layer; +} + +CacheFileLayer *BKE_cachefile_get_active_layer(CacheFile *cache_file) +{ + return BLI_findlink(&cache_file->layers, cache_file->active_layer - 1); +} + +void BKE_cachefile_remove_layer(CacheFile *cache_file, CacheFileLayer *layer) +{ + cache_file->active_layer = 0; + BLI_remlink(&cache_file->layers, layer); + MEM_freeN(layer); +} diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9ce07cd2e07..3796fa51499 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -2426,6 +2426,13 @@ void uiTemplateCacheFileProcedural(uiLayout *layout, */ void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr); +/** + * Draw the override layers related properties of the CacheFile. + */ +void uiTemplateCacheFileLayers(uiLayout *layout, + const struct bContext *C, + struct PointerRNA *fileptr); + /* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */ #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list" enum uiTemplateListFlags { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 923f741e3ae..2d1138b46a7 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -1528,6 +1528,9 @@ uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_bl uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block, const uiTreeViewItemHandle *new_item_handle); +/* interface_templates.c */ +struct uiListType *UI_UL_cache_file_layers(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc index 13e539b5095..817599605a9 100644 --- a/source/blender/editors/interface/interface_template_list.cc +++ b/source/blender/editors/interface/interface_template_list.cc @@ -1322,6 +1322,7 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list, void ED_uilisttypes_ui() { WM_uilisttype_add(UI_UL_asset_view()); + WM_uilisttype_add(UI_UL_cache_file_layers()); } /** \} */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 00e9a75848a..8330f8c0db7 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6474,6 +6474,67 @@ void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr) uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence")); } +static void cache_file_layer_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, "hide_layer", UI_ITEM_R_NO_BG, "", ICON_NONE); + uiItemR(row, itemptr, "filepath", UI_ITEM_R_NO_BG, "", ICON_NONE); +} + +uiListType *UI_UL_cache_file_layers() +{ + uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__); + + BLI_strncpy(list_type->idname, "UI_UL_cache_file_layers", sizeof(list_type->idname)); + list_type->draw_item = cache_file_layer_item; + + return list_type; +} + +void uiTemplateCacheFileLayers(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_layers", + "cache_file_layers", + fileptr, + "layers", + fileptr, + "active_index", + "", + 1, + 5, + UILST_LAYOUT_DEFAULT, + 1, + UI_TEMPLATE_LIST_FLAG_NONE); + + col = uiLayoutColumn(row, true); + uiItemO(col, "", ICON_ADD, "cachefile.layer_add"); + uiItemO(col, "", ICON_REMOVE, "cachefile.layer_remove"); + + CacheFile *file = fileptr->data; + if (BLI_listbase_count(&file->layers) > 1) { + uiItemS_ex(col, 1.0f); + uiItemO(col, "", ICON_TRIA_UP, "cachefile.layer_move"); + uiItemO(col, "", ICON_TRIA_DOWN, "cachefile.layer_move"); + } +} + bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr) { PropertyRNA *prop = RNA_struct_find_property(ptr, propname); diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index bf20c1f6438..4f71a804986 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -26,6 +26,7 @@ #include "DNA_cachefile_types.h" #include "DNA_space_types.h" +#include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" @@ -36,6 +37,7 @@ #include "BKE_report.h" #include "RNA_access.h" +#include "RNA_define.h" #include "DEG_depsgraph.h" @@ -46,6 +48,12 @@ #include "io_cache.h" +static void reload_cachefile(bContext *C, CacheFile *cache_file) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + BKE_cachefile_reload(depsgraph, cache_file); +} + static void cachefile_init(bContext *C, wmOperator *op) { PropertyPointerRNA *pprop; @@ -146,8 +154,7 @@ static int cachefile_reload_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - BKE_cachefile_reload(depsgraph, cache_file); + reload_cachefile(C, cache_file); return OPERATOR_FINISHED; } @@ -164,3 +171,160 @@ void CACHEFILE_OT_reload(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/* ***************************** Add Layer Operator **************************** */ + +static int cachefile_layer_open_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + char filepath[FILE_MAX]; + Main *bmain = CTX_data_main(C); + + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); + BLI_path_extension_replace(filepath, sizeof(filepath), ".abc"); + RNA_string_set(op->ptr, "filepath", filepath); + } + + /* There is no more CacheFile set when returning from the file selector, so store it here. */ + op->customdata = CTX_data_edit_cachefile(C); + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; + + UNUSED_VARS(event); +} + +static int cachefile_layer_add_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + CacheFile *cache_file = op->customdata; + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filename); + + if (!layer) { + WM_report(RPT_ERROR, "Could not add a layer to the cache file"); + return OPERATOR_CANCELLED; + } + + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_add(wmOperatorType *ot) +{ + ot->name = "Add layer"; + ot->description = "Add an override layer to the archive"; + ot->idname = "CACHEFILE_OT_layer_add"; + + /* api callbacks */ + ot->invoke = cachefile_layer_open_invoke; + ot->exec = cachefile_layer_add_exec; + + WM_operator_properties_filesel(ot, + FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +/* ***************************** Remove Layer Operator **************************** */ + +static int cachefile_layer_remove_exec(bContext *C, wmOperator *UNUSED(op)) +{ + CacheFile *cache_file = CTX_data_edit_cachefile(C); + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file); + BKE_cachefile_remove_layer(cache_file, layer); + + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_remove(wmOperatorType *ot) +{ + ot->name = "Add layer"; + ot->description = "Remove an override layer to the archive"; + ot->idname = "CACHEFILE_OT_layer_remove"; + + /* api callbacks */ + ot->exec = cachefile_layer_remove_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ***************************** Move Layer Operator **************************** */ + +static int cachefile_layer_move_exec(bContext *C, wmOperator *op) +{ + CacheFile *cache_file = CTX_data_edit_cachefile(C); + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file); + + if (!layer) { + return OPERATOR_CANCELLED; + } + + const int dir = RNA_enum_get(op->ptr, "direction"); + + if (BLI_listbase_link_move(&cache_file->layers, layer, dir)) { + cache_file->active_layer = BLI_findindex(&cache_file->layers, layer) + 1; + /* Only reload if something moved, might be expensive. */ + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + } + + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_move(wmOperatorType *ot) +{ + static const EnumPropertyItem layer_slot_move[] = { + {-1, "UP", 0, "Up", ""}, + {1, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + ot->name = "Move layer"; + ot->description = + "Move layer in the list, layers further down the list will overwrite data from the layers " + "higher up"; + ot->idname = "CACHEFILE_OT_layer_move"; + + /* api callbacks */ + ot->exec = cachefile_layer_move_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, + "direction", + layer_slot_move, + 0, + "Direction", + "Direction to move the active vertex group towards"); +} diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h index be6e31842af..297e065434f 100644 --- a/source/blender/editors/io/io_cache.h +++ b/source/blender/editors/io/io_cache.h @@ -27,3 +27,7 @@ struct wmOperatorType; void CACHEFILE_OT_open(struct wmOperatorType *ot); void CACHEFILE_OT_reload(struct wmOperatorType *ot); + +void CACHEFILE_OT_layer_add(struct wmOperatorType *ot); +void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot); +void CACHEFILE_OT_layer_move(struct wmOperatorType *ot); diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index 5dff0b69c2a..d9bbd7d8692 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -69,5 +69,10 @@ void ED_operatortypes_io(void) WM_operatortype_append(CACHEFILE_OT_open); WM_operatortype_append(CACHEFILE_OT_reload); + + WM_operatortype_append(CACHEFILE_OT_layer_add); + WM_operatortype_append(CACHEFILE_OT_layer_remove); + WM_operatortype_append(CACHEFILE_OT_layer_move); + WM_operatortype_append(WM_OT_obj_export); } diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index c1f3add377b..18b0c91b67c 100644 --- a/source/blender/io/alembic/ABC_alembic.h +++ b/source/blender/io/alembic/ABC_alembic.h @@ -26,6 +26,7 @@ extern "C" { #endif struct CacheArchiveHandle; +struct CacheFileLayer; struct CacheReader; struct ListBase; struct Main; @@ -102,6 +103,7 @@ bool ABC_import(struct bContext *C, struct CacheArchiveHandle *ABC_create_handle(struct Main *bmain, const char *filename, + const struct CacheFileLayer *layers, struct ListBase *object_paths); void ABC_free_handle(struct CacheArchiveHandle *handle); diff --git a/source/blender/io/alembic/intern/abc_reader_archive.cc b/source/blender/io/alembic/intern/abc_reader_archive.cc index 4951dc0e035..94def041285 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.cc +++ b/source/blender/io/alembic/intern/abc_reader_archive.cc @@ -23,6 +23,8 @@ #include "abc_reader_archive.h" +#include "Alembic/AbcCoreLayer/Read.h" + #include "BKE_main.h" #include "BLI_path_util.h" @@ -76,6 +78,46 @@ static IArchive open_archive(const std::string &filename, return IArchive(); } +ArchiveReader *ArchiveReader::get(struct Main *bmain, const std::vector<const char *> &filenames) +{ + std::vector<ArchiveReader *> readers; + + for (const char *filename : filenames) { + auto reader = new ArchiveReader(bmain, filename); + + if (!reader->valid()) { + delete reader; + continue; + } + + readers.push_back(reader); + } + + if (readers.size() == 0) { + return nullptr; + } + + if (readers.size() == 1) { + return readers[0]; + } + + return new ArchiveReader(readers); +} + +ArchiveReader::ArchiveReader(const std::vector<ArchiveReader *> &readers) : m_readers(readers) +{ + Alembic::AbcCoreLayer::ArchiveReaderPtrs archives; + + for (auto &reader : readers) { + archives.push_back(reader->m_archive.getPtr()); + } + + Alembic::AbcCoreLayer::ReadArchive layer; + Alembic::AbcCoreAbstract::ArchiveReaderPtr arPtr = layer(archives); + + m_archive = IArchive(arPtr, kWrapExisting, ErrorHandler::kThrowPolicy); +} + ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename) { char abs_filename[FILE_MAX]; @@ -96,6 +138,13 @@ ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename) m_archive = open_archive(abs_filename, m_streams); } +ArchiveReader::~ArchiveReader() +{ + for (ArchiveReader *reader : m_readers) { + delete reader; + } +} + bool ArchiveReader::valid() const { return m_archive.valid(); diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h index 67000194aa1..937e3a190cf 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.h +++ b/source/blender/io/alembic/intern/abc_reader_archive.h @@ -41,9 +41,17 @@ class ArchiveReader { std::ifstream m_infile; std::vector<std::istream *> m_streams; - public: + std::vector<ArchiveReader *> m_readers; + + ArchiveReader(const std::vector<ArchiveReader *> &readers); + ArchiveReader(struct Main *bmain, const char *filename); + public: + static ArchiveReader *get(struct Main *bmain, const std::vector<const char *> &filenames); + + ~ArchiveReader(); + bool valid() const; Alembic::Abc::IObject getTop(); diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index d7b176eea50..58fc4dd599d 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -159,11 +159,25 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths) CacheArchiveHandle *ABC_create_handle(struct Main *bmain, const char *filename, + const CacheFileLayer *layers, ListBase *object_paths) { - ArchiveReader *archive = new ArchiveReader(bmain, filename); + std::vector<const char *> filenames; + filenames.push_back(filename); - if (!archive->valid()) { + while (layers) { + if ((layers->flag & CACHEFILE_LAYER_HIDDEN) == 0) { + filenames.push_back(layers->filepath); + } + layers = layers->next; + } + + /* We need to reverse the order as overriding archives should come first. */ + std::reverse(filenames.begin(), filenames.end()); + + ArchiveReader *archive = ArchiveReader::get(bmain, filenames); + + if (!archive || !archive->valid()) { delete archive; return nullptr; } @@ -447,9 +461,9 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa WM_set_locked_interface(data->wm, true); - ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename); + ArchiveReader *archive = ArchiveReader::get(data->bmain, {data->filename}); - if (!archive->valid()) { + if (!archive || !archive->valid()) { data->error_code = ABC_ARCHIVE_FAIL; delete archive; return; diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index 0f4c53a6e7e..65e1dd6c096 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -59,6 +59,18 @@ typedef struct CacheObjectPath { char path[4096]; } CacheObjectPath; +/* CacheFileLayer::flag */ +enum { CACHEFILE_LAYER_HIDDEN = (1 << 0) }; + +typedef struct CacheFileLayer { + struct CacheFileLayer *next, *prev; + + /** 1024 = FILE_MAX. */ + char filepath[1024]; + int flag; + int _pad; +} CacheFileLayer; + /* CacheFile::velocity_unit * Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */ enum { @@ -73,6 +85,8 @@ typedef struct CacheFile { /** Paths of the objects inside of the archive referenced by this CacheFile. */ ListBase object_paths; + ListBase layers; + /** 1024 = FILE_MAX. */ char filepath[1024]; @@ -109,7 +123,10 @@ typedef struct CacheFile { /** Size in megabytes for the prefetch cache used by the Cycles Procedural. */ int prefetch_cache_size; - char _pad2[7]; + /** Index of the currently selected layer in the UI, starts at 1. */ + int active_layer; + + char _pad2[3]; char velocity_unit; /* Name of the velocity property in the archive. */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index b32d98e3cb1..1ade964854d 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -105,6 +105,7 @@ extern StructRNA RNA_BuildModifier; extern StructRNA RNA_ByteColorAttribute; extern StructRNA RNA_ByteColorAttributeValue; extern StructRNA RNA_CacheFile; +extern StructRNA RNA_CacheFileLayer; extern StructRNA RNA_Camera; extern StructRNA RNA_CameraDOFSettings; extern StructRNA RNA_CastModifier; diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index 74d924b8937..2f8fc004d85 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -32,6 +32,7 @@ #ifdef RNA_RUNTIME +# include "BLI_math.h" # include "BLI_string.h" # include "BKE_cachefile.h" @@ -54,6 +55,14 @@ static void rna_CacheFile_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); } +static void rna_CacheFileLayer_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) { rna_CacheFile_update(bmain, scene, ptr); @@ -66,6 +75,91 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL); } +static PointerRNA rna_CacheFile_active_layer_get(PointerRNA *ptr) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + return rna_pointer_inherit_refine( + ptr, &RNA_CacheFileLayer, BKE_cachefile_get_active_layer(cache_file)); +} + +static void rna_CacheFile_active_layer_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *reports) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + int index = BLI_findindex(&cache_file->layers, value.data); + if (index == -1) { + BKE_reportf(reports, + RPT_ERROR, + "Layer '%s' not found in object '%s'", + ((CacheFileLayer *)value.data)->filepath, + cache_file->id.name + 2); + return; + } + + cache_file->active_layer = index + 1; +} + +static int rna_CacheFile_active_layer_index_get(PointerRNA *ptr) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + return cache_file->active_layer - 1; +} + +static void rna_CacheFile_active_layer_index_set(PointerRNA *ptr, int value) +{ + CacheFile *cache_file = (CacheFile *)ptr->owner_id; + cache_file->active_layer = value + 1; +} + +static void rna_CacheFile_active_layer_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->layers) - 1); +} + +static void rna_CacheFileLayer_hidden_flag_set(PointerRNA *ptr, const bool value) +{ + CacheFileLayer *layer = (CacheFileLayer *)ptr->data; + + if (value) { + layer->flag |= CACHEFILE_LAYER_HIDDEN; + } + else { + layer->flag &= ~CACHEFILE_LAYER_HIDDEN; + } +} + +static CacheFileLayer *rna_CacheFile_layer_new(CacheFile *cache_file, + bContext *C, + ReportList *reports, + const char *filepath) +{ + CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filepath); + if (layer == NULL) { + BKE_reportf( + reports, RPT_ERROR, "Cannot add a layer 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 layer; +} + +static void rna_CacheFile_layer_remove(CacheFile *cache_file, bContext *C, PointerRNA *layer_ptr) +{ + CacheFileLayer *layer = layer_ptr->data; + BKE_cachefile_remove_layer(cache_file, layer); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + BKE_cachefile_reload(depsgraph, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); +} + #else /* cachefile.object_paths */ @@ -94,6 +188,61 @@ static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_struct_ui_text(srna, "Object Paths", "Collection of object paths"); } +static void rna_def_cachefile_layer(BlenderRNA *brna) +{ + StructRNA *srna = RNA_def_struct(brna, "CacheFileLayer", NULL); + RNA_def_struct_sdna(srna, "CacheFileLayer"); + RNA_def_struct_ui_text( + srna, + "Cache Layer", + "Layer of the cache, used to load or override data from the first the first layer"); + + PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); + RNA_def_property_ui_text(prop, "File Path", "Path to the archive"); + RNA_def_property_update(prop, 0, "rna_CacheFileLayer_update"); + + prop = RNA_def_property(srna, "hide_layer", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CACHEFILE_LAYER_HIDDEN); + RNA_def_property_boolean_funcs(prop, NULL, "rna_CacheFileLayer_hidden_flag_set"); + RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1); + RNA_def_property_ui_text(prop, "Hide Layer", "Do not load data from this layer"); + RNA_def_property_update(prop, 0, "rna_CacheFileLayer_update"); +} + +static void rna_def_cachefile_layers(BlenderRNA *brna, PropertyRNA *cprop) +{ + RNA_def_property_srna(cprop, "CacheFileLayers"); + StructRNA *srna = RNA_def_struct(brna, "CacheFileLayers", NULL); + RNA_def_struct_sdna(srna, "CacheFile"); + RNA_def_struct_ui_text(srna, "Cache Layers", "Collection of cache layers"); + + PropertyRNA *prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "CacheFileLayer"); + RNA_def_property_pointer_funcs( + prop, "rna_CacheFile_active_layer_get", "rna_CacheFile_active_layer_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Active Layer", "Active layer of the CacheFile"); + + /* Add a layer. */ + FunctionRNA *func = RNA_def_function(srna, "new", "rna_CacheFile_layer_new"); + RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Add a new layer"); + PropertyRNA *parm = RNA_def_string( + func, "filepath", "File Path", 0, "", "File path to the archive used as a layer"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* Return type. */ + parm = RNA_def_pointer(func, "layer", "CacheFileLayer", "", "Newly created layer"); + RNA_def_function_return(func, parm); + + /* Remove a layer. */ + func = RNA_def_function(srna, "remove", "rna_CacheFile_layer_remove"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Remove an existing layer from the cache file"); + parm = RNA_def_pointer(func, "layer", "CacheFileLayer", "", "Layer to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); +} + static void rna_def_cachefile(BlenderRNA *brna) { StructRNA *srna = RNA_def_struct(brna, "CacheFile", "ID"); @@ -234,6 +383,23 @@ static void rna_def_cachefile(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_CacheFile_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + /* ----------------- Alembic Layers ----------------- */ + + prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "layers", NULL); + RNA_def_property_struct_type(prop, "CacheFileLayer"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_ui_text(prop, "Cache Layers", "Layers of the cache"); + rna_def_cachefile_layers(brna, prop); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_int_sdna(prop, NULL, "active_layer"); + RNA_def_property_int_funcs(prop, + "rna_CacheFile_active_layer_index_get", + "rna_CacheFile_active_layer_index_set", + "rna_CacheFile_active_layer_index_range"); + RNA_define_lib_overridable(false); rna_def_cachefile_object_paths(brna, prop); @@ -245,6 +411,7 @@ void RNA_def_cachefile(BlenderRNA *brna) { rna_def_cachefile(brna); rna_def_alembic_object_path(brna); + rna_def_cachefile_layer(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index a406e867d6c..5bf778d1962 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -619,6 +619,19 @@ static void rna_uiTemplateCacheFileTimeSettings(uiLayout *layout, uiTemplateCacheFileTimeSettings(layout, &fileptr); } +static void rna_uiTemplateCacheFileLayers(uiLayout *layout, + bContext *C, + PointerRNA *ptr, + const char *propname) +{ + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) { + return; + } + + uiTemplateCacheFileLayers(layout, C, &fileptr); +} + static void rna_uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, @@ -1847,6 +1860,11 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Show cache files time settings"); api_ui_item_rna_common(func); + func = RNA_def_function(srna, "template_cache_file_layers", "rna_uiTemplateCacheFileLayers"); + RNA_def_function_ui_description(func, "Show cache files override layers properties"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + api_ui_item_rna_common(func); + func = RNA_def_function(srna, "template_recent_files", "uiTemplateRecentFiles"); RNA_def_function_ui_description(func, "Show list of recently saved .blend files"); RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX); diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 00f39e58b4d..e1459ccba6d 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -392,6 +392,22 @@ static void render_procedural_panel_draw(const bContext *C, Panel *panel) 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) { PanelType *panel_type = modifier_panel_register( @@ -405,6 +421,12 @@ static void panelRegister(ARegionType *region_type) panel_type); modifier_subpanel_register( region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type); + modifier_subpanel_register(region_type, + "override_layers", + "Override Layers", + NULL, + override_layers_panel_draw, + panel_type); } static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) |