From 61050f75b13ef706d3a80b86137436d3fb0bfa93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sat, 6 Aug 2016 06:20:37 +0200 Subject: Basic Alembic support All in all, this patch adds an Alembic importer, an Alembic exporter, and a new CacheFile data block which, for now, wraps around an Alembic archive. This data block is made available through a new modifier ("Mesh Sequence Cache") as well as a new constraint ("Transform Cache") to somewhat properly support respectively geometric and transformation data streaming from alembic caches. A more in-depth documentation is to be found on the wiki, as well as a guide to compile alembic: https://wiki.blender.org/index.php/ User:Kevindietrich/AlembicBasicIo. Many thanks to everyone involved in this little project, and huge shout out to "cgstrive" for the thorough testings with Maya, 3ds Max, Houdini and Realflow as well as @fjuhec, @jensverwiebe and @jasperge for the custom builds and compile fixes. Reviewers: sergey, campbellbarton, mont29 Reviewed By: sergey, campbellbarton, mont29 Differential Revision: https://developer.blender.org/D2060 --- .../editors/animation/anim_channels_defines.c | 84 ++++ .../blender/editors/animation/anim_channels_edit.c | 5 + source/blender/editors/animation/anim_filter.c | 72 +++- source/blender/editors/animation/keyframes_draw.c | 32 ++ source/blender/editors/include/ED_anim_api.h | 2 + source/blender/editors/include/ED_keyframes_draw.h | 3 + source/blender/editors/include/UI_interface.h | 1 + source/blender/editors/interface/interface_icons.c | 2 + .../editors/interface/interface_templates.c | 72 ++++ source/blender/editors/io/CMakeLists.txt | 14 + source/blender/editors/io/io_alembic.c | 458 +++++++++++++++++++++ source/blender/editors/io/io_alembic.h | 37 ++ source/blender/editors/io/io_cache.c | 162 ++++++++ source/blender/editors/io/io_cache.h | 37 ++ source/blender/editors/io/io_ops.c | 16 +- source/blender/editors/object/object_constraint.c | 7 + source/blender/editors/space_file/filelist.c | 7 + source/blender/editors/space_file/filesel.c | 4 +- source/blender/editors/space_nla/nla_buttons.c | 1 + source/blender/editors/space_nla/nla_channels.c | 1 + .../blender/editors/space_outliner/outliner_draw.c | 2 + .../editors/space_outliner/outliner_intern.h | 2 +- .../blender/editors/space_outliner/outliner_tree.c | 11 + source/blender/editors/space_time/space_time.c | 65 ++- 24 files changed, 1092 insertions(+), 5 deletions(-) create mode 100644 source/blender/editors/io/io_alembic.c create mode 100644 source/blender/editors/io/io_alembic.h create mode 100644 source/blender/editors/io/io_cache.c create mode 100644 source/blender/editors/io/io_cache.h (limited to 'source/blender/editors') diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 752544f65e1..3085e383909 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -40,6 +40,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_cachefile_types.h" #include "DNA_camera_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" @@ -1577,6 +1578,88 @@ static bAnimChannelType ACF_DSTEX = /* Camera Expander ------------------------------------------- */ +// TODO: just get this from RNA? +static int acf_dscachefile_icon(bAnimListElem *ale) +{ + UNUSED_VARS(ale); + return ICON_FILE; +} + +/* get the appropriate flag(s) for the setting when it is valid */ +static int acf_dscachefile_setting_flag(bAnimContext *ac, eAnimChannel_Settings setting, bool *neg) +{ + /* clear extra return data first */ + *neg = false; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return CACHEFILE_DS_EXPAND; + + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; + + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; + + default: /* unsupported */ + return 0; + } + + UNUSED_VARS(ac); +} + +/* get pointer to the setting */ +static void *acf_dscachefile_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +{ + CacheFile *cache_file = (CacheFile *)ale->data; + + /* clear extra return data first */ + *type = 0; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(cache_file->flag, type); + + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (cache_file->adt) { + return GET_ACF_FLAG_PTR(cache_file->adt->flag, type); + } + + return NULL; + + default: /* unsupported */ + return NULL; + } +} + +/* CacheFile expander type define. */ +static bAnimChannelType ACF_DSCACHEFILE = +{ + "Cache File Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_generic_dataexpand_color, /* backdrop color */ + acf_generic_dataexpand_backdrop, /* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_generic_basic_offset, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_generic_idfill_name_prop, /* name prop */ + acf_dscachefile_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dscachefile_setting_flag, /* flag for setting */ + acf_dscachefile_setting_ptr /* pointer for setting */ +}; + +/* Camera Expander ------------------------------------------- */ + // TODO: just get this from RNA? static int acf_dscam_icon(bAnimListElem *UNUSED(ale)) { @@ -3388,6 +3471,7 @@ static void ANIM_init_channel_typeinfo_data(void) animchannelTypeInfo[type++] = &ACF_DSMAT; /* Material Channel */ animchannelTypeInfo[type++] = &ACF_DSLAM; /* Lamp Channel */ animchannelTypeInfo[type++] = &ACF_DSCAM; /* Camera Channel */ + animchannelTypeInfo[type++] = &ACF_DSCACHEFILE; /* CacheFile Channel */ animchannelTypeInfo[type++] = &ACF_DSCUR; /* Curve Channel */ animchannelTypeInfo[type++] = &ACF_DSSKEY; /* ShapeKey Channel */ animchannelTypeInfo[type++] = &ACF_DSWOR; /* World Channel */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 1a59acb2aeb..cb65a9aecad 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -120,6 +120,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ case ANIMTYPE_DSLAM: case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: case ANIMTYPE_DSCUR: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: @@ -175,6 +176,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ case ANIMTYPE_DSLAM: case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: case ANIMTYPE_DSCUR: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: @@ -275,6 +277,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ case ANIMTYPE_DSLAM: case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: case ANIMTYPE_DSCUR: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: @@ -370,6 +373,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ case ANIMTYPE_DSLAM: case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: case ANIMTYPE_DSCUR: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: @@ -2716,6 +2720,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ case ANIMTYPE_DSLAM: case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: case ANIMTYPE_DSCUR: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 88d96c531e0..5cd305f69f5 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -53,6 +53,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_camera_types.h" +#include "DNA_cachefile_types.h" #include "DNA_lamp_types.h" #include "DNA_lattice_types.h" #include "DNA_linestyle_types.h" @@ -199,6 +200,16 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction) ac->mode = saction->mode; return true; + + case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + saction->ads.source = (ID *)ac->scene; + + ac->datatype = ANIMCONT_CHANNEL; + ac->data = &saction->ads; + + ac->mode = saction->mode; + return true; case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */ { @@ -660,6 +671,19 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne ale->adt = BKE_animdata_from_id(data); break; } + case ANIMTYPE_DSCACHEFILE: + { + CacheFile *cache_file = (CacheFile *)data; + AnimData *adt = cache_file->adt; + + ale->flag = FILTER_CACHEFILE_OBJD(cache_file); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } case ANIMTYPE_DSCUR: { Curve *cu = (Curve *)data; @@ -1751,6 +1775,42 @@ static size_t animdata_filter_ds_gpencil(bAnimContext *ac, ListBase *anim_data, return items; } +/* Helper for Cache File data integrated with main DopeSheet */ +static size_t animdata_filter_ds_cachefile(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, CacheFile *cache_file, int filter_mode) +{ + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* add relevant animation channels for Cache File */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_CACHEFILE_OBJD(cache_file)) + { + /* add animation channels */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, &cache_file->id, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include data-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by active status */ + // XXX: active check here needs checking + if (ANIMCHANNEL_ACTIVEOK(cache_file)) { + ANIMCHANNEL_NEW_CHANNEL(cache_file, ANIMTYPE_DSCACHEFILE, cache_file); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; +} + /* Helper for Mask Editing - mask layers */ static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const int filter_mode) { @@ -2839,6 +2899,12 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b filter_mode |= ANIMFILTER_SELEDIT; } + /* Cache files level animations (frame duration and such). */ + CacheFile *cache_file = G.main->cachefiles.first; + for (; cache_file; cache_file = cache_file->id.next) { + items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode); + } + /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */ items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode); @@ -2950,7 +3016,11 @@ static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bD case ANIMTYPE_OBJECT: items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode); break; - + + case ANIMTYPE_DSCACHEFILE: + items += animdata_filter_ds_cachefile(ac, anim_data, ads, channel->data, filter_mode); + break; + case ANIMTYPE_ANIMDATA: items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode); break; diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 6e776953356..5f675e690b9 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -44,6 +44,7 @@ #include "BLI_utildefines.h" #include "DNA_anim_types.h" +#include "DNA_cachefile_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_gpencil_types.h" @@ -965,6 +966,37 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl ANIM_animdata_freelist(&anim_data); } +void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, DLRBT_Tree *blocks) +{ + if (cache_file == NULL) { + return; + } + + /* create a dummy wrapper data to work with */ + bAnimListElem dummychan = {NULL}; + dummychan.type = ANIMTYPE_DSCACHEFILE; + dummychan.data = cache_file; + dummychan.id = &cache_file->id; + dummychan.adt = cache_file->adt; + + bAnimContext ac = {NULL}; + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; + + /* get F-Curves to take keyframes from */ + ListBase anim_data = { NULL, NULL }; + int filter = ANIMFILTER_DATA_VISIBLE; // curves only + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* loop through each F-Curve, grabbing the keyframes */ + for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) { + fcurve_to_keylist(ale->adt, ale->data, keys, blocks); + } + + ANIM_animdata_freelist(&anim_data); +} + void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree *blocks) { BezTriple *bezt; diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 0940f594482..bfd89e90fce 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -156,6 +156,7 @@ typedef enum eAnim_ChannelType { ANIMTYPE_DSMAT, ANIMTYPE_DSLAM, ANIMTYPE_DSCAM, + ANIMTYPE_DSCACHEFILE, ANIMTYPE_DSCUR, ANIMTYPE_DSSKEY, ANIMTYPE_DSWOR, @@ -275,6 +276,7 @@ typedef enum eAnimFilter_Flags { #define FILTER_MAT_OBJD(ma) (CHECK_TYPE_INLINE(ma, Material *), ((ma->flag & MA_DS_EXPAND))) #define FILTER_LAM_OBJD(la) (CHECK_TYPE_INLINE(la, Lamp *), ((la->flag & LA_DS_EXPAND))) #define FILTER_CAM_OBJD(ca) (CHECK_TYPE_INLINE(ca, Camera *), ((ca->flag & CAM_DS_EXPAND))) +#define FILTER_CACHEFILE_OBJD(cf) (CHECK_TYPE_INLINE(cf, CacheFile *), ((cf->flag & CACHEFILE_DS_EXPAND))) #define FILTER_CUR_OBJD(cu) (CHECK_TYPE_INLINE(cu, Curve *), ((cu->flag & CU_DS_EXPAND))) #define FILTER_PART_OBJD(part) (CHECK_TYPE_INLINE(part, ParticleSettings *), ((part->flag & PART_DS_EXPAND))) #define FILTER_MBALL_OBJD(mb) (CHECK_TYPE_INLINE(mb, MetaBall *), ((mb->flag2 & MB_DS_EXPAND))) diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index b1f3f012e09..c478a8b17e5 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -34,6 +34,7 @@ struct bAnimContext; struct AnimData; +struct CacheFile; struct FCurve; struct bDopeSheet; struct bAction; @@ -141,6 +142,8 @@ void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct D void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); /* Object */ void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); +/* Cache File */ +void cachefile_to_keylist(struct bDopeSheet *ads, struct CacheFile *cache_file, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); /* Scene */ void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); /* DopeSheet Summary */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index f77e795adca..1f053c806b0 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -945,6 +945,7 @@ void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C); void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr); void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name); void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color); +void uiTemplateCacheFile(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname); /* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */ #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list" diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 4107414a240..22a450d2523 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1541,6 +1541,8 @@ int UI_idcode_icon_get(const int idcode) return ICON_BRUSH_DATA; case ID_CA: return ICON_CAMERA_DATA; + case ID_CF: + return ICON_FILE; case ID_CU: return ICON_CURVE_DATA; case ID_GD: diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 58cadf5587a..52283776816 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -32,6 +32,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_cachefile_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -368,6 +369,7 @@ static const char *template_id_browse_tip(StructRNA *type) case ID_MSK: return N_("Browse Mask to be linked"); case ID_PAL: return N_("Browse Palette Data to be linked"); case ID_PC: return N_("Browse Paint Curve Data to be linked"); + case ID_CF: return N_("Browse Cache Files to be linked"); } } return N_("Browse ID data to be linked"); @@ -3848,3 +3850,73 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color) UI_block_align_end(block); } + +/********************************* Cache File *********************************/ + +void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname) +{ + if (!ptr->data) { + return; + } + + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); + + if (!prop) { + printf("%s: property not found: %s.%s\n", + __func__, RNA_struct_identifier(ptr->type), propname); + return; + } + + if (RNA_property_type(prop) != PROP_POINTER) { + printf("%s: expected pointer property for %s.%s\n", + __func__, RNA_struct_identifier(ptr->type), propname); + return; + } + + PointerRNA fileptr = RNA_property_pointer_get(ptr, prop); + CacheFile *file = fileptr.data; + + uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr); + + uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL); + + if (!file) { + return; + } + + uiLayout *row = uiLayoutRow(layout, false); + uiBlock *block = uiLayoutGetBlock(row); + uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, ""); + + row = uiLayoutRow(layout, false); + uiLayout *split = uiLayoutSplit(row, 0.0f, false); + row = uiLayoutRow(split, true); + + uiItemR(row, &fileptr, "filepath", 0, "", ICON_NONE); + uiItemO(row, "", ICON_FILE_REFRESH, "cachefile.reload"); + + row = uiLayoutRow(layout, false); + uiItemR(row, &fileptr, "is_sequence", 0, "Is Sequence", ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemR(row, &fileptr, "override_frame", 0, "Override Frame", ICON_NONE); + + row = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row, RNA_boolean_get(&fileptr, "override_frame")); + uiItemR(row, &fileptr, "frame", 0, "Frame", ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE); + + /* TODO: unused for now, so no need to expose. */ +#if 0 + row = uiLayoutRow(layout, false); + uiItemR(row, &fileptr, "forward_axis", 0, "Forward Axis", ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemR(row, &fileptr, "up_axis", 0, "Up Axis", ICON_NONE); +#endif +} diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index 828cb494eab..b3bbce939a5 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -28,6 +28,8 @@ set(INC ../../makesrna ../../windowmanager ../../collada + ../../alembic + ../../../../intern/guardedalloc ) set(INC_SYS @@ -35,9 +37,13 @@ set(INC_SYS ) set(SRC + io_alembic.c + io_cache.c io_collada.c io_ops.c + io_alembic.h + io_cache.h io_collada.h io_ops.h ) @@ -46,6 +52,14 @@ if(WITH_OPENCOLLADA) add_definitions(-DWITH_COLLADA) endif() +if(WITH_ALEMBIC) + add_definitions(-DWITH_ALEMBIC) + + if(WITH_ALEMBIC_HDF5) + add_definitions(-DWITH_ALEMBIC_HDF5) + endif() +endif() + if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c new file mode 100644 index 00000000000..7a7c42e501b --- /dev/null +++ b/source/blender/editors/io/io_alembic.c @@ -0,0 +1,458 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifdef WITH_ALEMBIC + +/* needed for directory lookup */ +#ifndef WIN32 +# include +#else +# include "BLI_winstuff.h" +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "BLI_listbase.h" +#include "BLI_math_vector.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "io_alembic.h" + +#include "ABC_alembic.h" + +static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + char filepath[FILE_MAX]; + BLI_strncpy(filepath, G.main->name, sizeof(filepath)); + BLI_replace_extension(filepath, sizeof(filepath), ".abc"); + RNA_string_set(op->ptr, "filepath", filepath); + } + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; + + UNUSED_VARS(event); +} + +static int wm_alembic_export_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + const struct AlembicExportParams params = { + .frame_start = RNA_int_get(op->ptr, "start"), + .frame_end = RNA_int_get(op->ptr, "end"), + + .frame_step_xform = 1.0 / (double)RNA_int_get(op->ptr, "xsamples"), + .frame_step_shape = 1.0 / (double)RNA_int_get(op->ptr, "gsamples"), + + .shutter_open = RNA_float_get(op->ptr, "sh_open"), + .shutter_close = RNA_float_get(op->ptr, "sh_close"), + + .selected_only = RNA_boolean_get(op->ptr, "selected"), + .uvs = RNA_boolean_get(op->ptr, "uvs"), + .normals = RNA_boolean_get(op->ptr, "normals"), + .vcolors = RNA_boolean_get(op->ptr, "vcolors"), + .apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv"), + .flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"), + .visible_layers_only = RNA_boolean_get(op->ptr, "visible_layers_only"), + .renderable_only = RNA_boolean_get(op->ptr, "renderable_only"), + .face_sets = RNA_boolean_get(op->ptr, "face_sets"), + .use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"), + .compression_type = RNA_enum_get(op->ptr, "compression_type"), + .packuv = RNA_boolean_get(op->ptr, "packuv"), + + .global_scale = RNA_float_get(op->ptr, "global_scale"), + }; + + ABC_export(CTX_data_scene(C), C, filename, ¶ms); + + return OPERATOR_FINISHED; +} + +static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr) +{ + uiLayout *box = uiLayoutBox(layout); + uiLayout *row; + +#ifdef WITH_ALEMBIC_HDF5 + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Archive Options:"), ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "compression_type", 0, NULL, ICON_NONE); +#endif + + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "global_scale", 0, NULL, ICON_NONE); + + /* Scene Options */ + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Scene Options:"), ICON_SCENE_DATA); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "start", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "end", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "xsamples", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "gsamples", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "sh_open", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "sh_close", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "renderable_only", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "visible_layers_only", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "flatten", 0, NULL, ICON_NONE); + + /* Object Data */ + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Object Options:"), ICON_OBJECT_DATA); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "uvs", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "packuv", 0, NULL, ICON_NONE); + uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "uvs")); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "normals", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "vcolors", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "face_sets", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "subdiv_schema", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "apply_subdiv", 0, NULL, ICON_NONE); +} + +static void wm_alembic_export_draw(bContext *UNUSED(C), wmOperator *op) +{ + PointerRNA ptr; + + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + ui_alembic_export_settings(op->layout, &ptr); +} + +void WM_OT_alembic_export(wmOperatorType *ot) +{ + ot->name = "Export Alembic Archive"; + ot->idname = "WM_OT_alembic_export"; + + ot->invoke = wm_alembic_export_invoke; + ot->exec = wm_alembic_export_exec; + ot->poll = WM_operator_winactive; + ot->ui = wm_alembic_export_draw; + + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC, + FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH, + FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); + + RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX, + "Start Frame", "Start Frame", INT_MIN, INT_MAX); + + RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX, + "End Frame", "End Frame", INT_MIN, INT_MAX); + + RNA_def_int(ot->srna, "xsamples", 1, 1, 128, + "Transform Samples", "Number of times per frame transformations are sampled", 1, 128); + + RNA_def_int(ot->srna, "gsamples", 1, 1, 128, + "Geometry Samples", "Number of times per frame object datas are sampled", 1, 128); + + RNA_def_float(ot->srna, "sh_open", 0.0f, -1.0f, 1.0f, + "Shutter Open", "Time at which the shutter is open", -1.0f, 1.0f); + + RNA_def_float(ot->srna, "sh_close", 1.0f, -1.0f, 1.0f, + "Shutter Close", "Time at which the shutter is closed", -1.0f, 1.0f); + + RNA_def_boolean(ot->srna, "selected", 0, + "Selected Objects Only", "Export only selected objects"); + + RNA_def_boolean(ot->srna, "renderable_only", 1, + "Renderable Objects Only", + "Export only objects marked renderable in the outliner"); + + RNA_def_boolean(ot->srna, "visible_layers_only", 0, + "Visible Layers Only", "Export only objects in visible layers"); + + RNA_def_boolean(ot->srna, "flatten", 0, + "Flatten Hierarchy", + "Do not preserve objects' parent/children relationship"); + + RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Export UVs"); + + RNA_def_boolean(ot->srna, "packuv", 1, "Pack UV Islands", + "Export UVs with packed island"); + + RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals"); + + RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex colors", "Export vertex colors"); + + RNA_def_boolean(ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments"); + + RNA_def_boolean(ot->srna, "subdiv_schema", 0, + "Use Subdivision Schema", + "Export meshes using Alembic's subdivision schema"); + + RNA_def_boolean(ot->srna, "apply_subdiv", 0, + "Apply Subsurf", "Export subdivision surfaces as meshes"); + + RNA_def_enum(ot->srna, "compression_type", rna_enum_abc_compression_items, + ABC_ARCHIVE_OGAWA, "Compression", ""); + + RNA_def_float(ot->srna, "global_scale", 1.0f, 0.0001f, 1000.0f, "Scale", + "Value by which to enlarge or shrink the objects with respect to the world's origin", + 0.0001f, 1000.0f); +} + +/* ************************************************************************** */ + +/* TODO(kevin): check on de-duplicating all this with code in image_ops.c */ + +typedef struct CacheFrame { + struct CacheFrame *next, *prev; + int framenr; +} CacheFrame; + +static int cmp_frame(const void *a, const void *b) +{ + const CacheFrame *frame_a = a; + const CacheFrame *frame_b = b; + + if (frame_a->framenr < frame_b->framenr) return -1; + if (frame_a->framenr > frame_b->framenr) return 1; + return 0; +} + +static int get_sequence_len(char *filename, int *ofs) +{ + int frame; + int numdigit; + + if (!BLI_path_frame_get(filename, &frame, &numdigit)) { + return 1; + } + + char path[FILE_MAX]; + BLI_split_dir_part(filename, path, FILE_MAX); + + DIR *dir = opendir(path); + + const char *ext = ".abc"; + const char *basename = BLI_path_basename(filename); + const int len = strlen(basename) - (numdigit + strlen(ext)); + + ListBase frames; + BLI_listbase_clear(&frames); + + struct dirent *fname; + while ((fname = readdir(dir)) != NULL) { + /* do we have the right extension? */ + if (!strstr(fname->d_name, ext)) { + continue; + } + + if (!STREQLEN(basename, fname->d_name, len)) { + continue; + } + + CacheFrame *cache_frame = MEM_callocN(sizeof(CacheFrame), "abc_frame"); + + BLI_path_frame_get(fname->d_name, &cache_frame->framenr, &numdigit); + + BLI_addtail(&frames, cache_frame); + } + + closedir(dir); + + BLI_listbase_sort(&frames, cmp_frame); + + CacheFrame *cache_frame = frames.first; + + if (cache_frame) { + int frame_curr = cache_frame->framenr; + (*ofs) = frame_curr; + + while (cache_frame && (cache_frame->framenr == frame_curr)) { + ++frame_curr; + cache_frame = cache_frame->next; + } + + BLI_freelistN(&frames); + + return frame_curr - (*ofs); + } + + return 1; +} + +/* ************************************************************************** */ + +static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr) +{ + uiLayout *box = uiLayoutBox(layout); + uiLayout *row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "scale", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Options:"), ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "is_sequence", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "validate_meshes", 0, NULL, ICON_NONE); +} + +static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op) +{ + PointerRNA ptr; + + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + ui_alembic_import_settings(op->layout, &ptr); +} + +static int wm_alembic_import_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + const float scale = RNA_float_get(op->ptr, "scale"); + const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence"); + const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range"); + const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes"); + + int offset = 0; + int sequence_len = 1; + + if (is_sequence) { + sequence_len = get_sequence_len(filename, &offset); + } + + ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes); + + return OPERATOR_FINISHED; +} + +void WM_OT_alembic_import(wmOperatorType *ot) +{ + ot->name = "Import Alembic Archive"; + ot->idname = "WM_OT_alembic_import"; + + ot->invoke = WM_operator_filesel; + ot->exec = wm_alembic_import_exec; + ot->poll = WM_operator_winactive; + ot->ui = wm_alembic_import_draw; + + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC, + FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH, + FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); + + RNA_def_float(ot->srna, "scale", 1.0f, 0.0001f, 1000.0f, "Scale", + "Value by which to enlarge or shrink the objects with respect to the world's origin", + 0.0001f, 1000.0f); + + RNA_def_boolean(ot->srna, "set_frame_range", true, + "Set Frame Range", + "If checked, update scene's start and end frame to match those of the Alembic archive"); + + RNA_def_boolean(ot->srna, "validate_meshes", 0, + "Validate Meshes", "Check imported mesh objects for invalid data (slow)"); + + RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence", + "Set to true if the cache is split into separate files"); +} + +#endif diff --git a/source/blender/editors/io/io_alembic.h b/source/blender/editors/io/io_alembic.h new file mode 100644 index 00000000000..5eefabef4be --- /dev/null +++ b/source/blender/editors/io/io_alembic.h @@ -0,0 +1,37 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifndef __IO_ALEMBIC_H__ +#define __IO_ALEMBIC_H__ + +/** \file blender/editors/io/io_alembic.h + * \ingroup editor/io + */ + +struct wmOperatorType; + +void WM_OT_alembic_export(struct wmOperatorType *ot); +void WM_OT_alembic_import(struct wmOperatorType *ot); + +#endif /* __IO_ALEMBIC_H__ */ diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c new file mode 100644 index 00000000000..d6e2c1ae204 --- /dev/null +++ b/source/blender/editors/io/io_cache.c @@ -0,0 +1,162 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_cachefile_types.h" +#include "DNA_space_types.h" + +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "BKE_cachefile.h" +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "io_cache.h" + +static void cachefile_init(bContext *C, wmOperator *op) +{ + PropertyPointerRNA *pprop; + + op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA"); + UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop); +} + +static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + char filepath[FILE_MAX]; + BLI_strncpy(filepath, G.main->name, sizeof(filepath)); + BLI_replace_extension(filepath, sizeof(filepath), ".abc"); + RNA_string_set(op->ptr, "filepath", filepath); + } + + cachefile_init(C, op); + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; + + UNUSED_VARS(event); +} + +static void open_cancel(bContext *UNUSED(C), wmOperator *op) +{ + MEM_freeN(op->customdata); + op->customdata = NULL; +} + +static int cachefile_open_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + Main *bmain = CTX_data_main(C); + + CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename)); + BLI_strncpy(cache_file->filepath, filename, FILE_MAX); + BKE_cachefile_reload(bmain, cache_file); + + /* hook into UI */ + PropertyPointerRNA *pprop = op->customdata; + + if (pprop->prop) { + /* when creating new ID blocks, use is already 1, but RNA + * pointer se also increases user, so this compensates it */ + id_us_min(&cache_file->id); + + PointerRNA idptr; + RNA_id_pointer_create(&cache_file->id, &idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_update(C, &pprop->ptr, pprop->prop); + } + + MEM_freeN(op->customdata); + + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_open(wmOperatorType *ot) +{ + ot->name = "Open Cache File"; + ot->idname = "CACHEFILE_OT_open"; + + ot->invoke = cachefile_open_invoke; + ot->exec = cachefile_open_exec; + ot->cancel = open_cancel; + + WM_operator_properties_filesel(ot, FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER, + FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH, + FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); +} + +/* ***************************** Reload Operator **************************** */ + +static int cachefile_reload_exec(bContext *C, wmOperator *op) +{ + CacheFile *cache_file = CTX_data_edit_cachefile(C); + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + Main *bmain = CTX_data_main(C); + + BLI_listbase_clear(&cache_file->object_paths); + BKE_cachefile_reload(bmain, cache_file); + + return OPERATOR_FINISHED; + + UNUSED_VARS(op); +} + +void CACHEFILE_OT_reload(wmOperatorType *ot) +{ + ot->name = "Refresh Archive"; + ot->description = "Update objects paths list with new data from the archive"; + ot->idname = "CACHEFILE_OT_reload"; + + /* api callbacks */ + ot->exec = cachefile_reload_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h new file mode 100644 index 00000000000..ea270c2aba1 --- /dev/null +++ b/source/blender/editors/io/io_cache.h @@ -0,0 +1,37 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifndef __IO_CACHE_H__ +#define __IO_CACHE_H__ + +/** \file blender/editors/io/io_cache.h + * \ingroup editor/io + */ + +struct wmOperatorType; + +void CACHEFILE_OT_open(struct wmOperatorType *ot); +void CACHEFILE_OT_reload(struct wmOperatorType *ot); + +#endif /* __IO_CACHE_H__ */ diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index a70a51a60be..d1e933517a9 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -30,11 +30,18 @@ #include "io_ops.h" /* own include */ +#include "WM_api.h" + #ifdef WITH_COLLADA # include "io_collada.h" -# include "WM_api.h" #endif +#ifdef WITH_ALEMBIC +# include "io_alembic.h" +#endif + +#include "io_cache.h" + void ED_operatortypes_io(void) { #ifdef WITH_COLLADA @@ -42,4 +49,11 @@ void ED_operatortypes_io(void) WM_operatortype_append(WM_OT_collada_export); WM_operatortype_append(WM_OT_collada_import); #endif +#ifdef WITH_ALEMBIC + WM_operatortype_append(WM_OT_alembic_import); + WM_operatortype_append(WM_OT_alembic_export); +#endif + + WM_operatortype_append(CACHEFILE_OT_open); + WM_operatortype_append(CACHEFILE_OT_reload); } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index db8a4c1960f..59d78f13ccb 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -416,6 +416,13 @@ static void test_constraint(Object *owner, bPoseChannel *pchan, bConstraint *con if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL)) con->flag |= CONSTRAINT_DISABLE; } + else if (con->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { + bTransformCacheConstraint *data = con->data; + + if ((data->cache_file == NULL) || (data->object_path[0] == '\0')) { + con->flag |= CONSTRAINT_DISABLE; + } + } /* Check targets for constraints */ if (check_targets && cti && cti->get_constraint_targets) { diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 5e9eb1f9207..b6e4991bf52 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -920,6 +920,8 @@ static int filelist_geticon_ex( return ICON_FILE_BLANK; else if (typeflag & FILE_TYPE_COLLADA) return ICON_FILE_BLANK; + else if (typeflag & FILE_TYPE_ALEMBIC) + return ICON_FILE_BLANK; else if (typeflag & FILE_TYPE_TEXT) return ICON_FILE_TEXT; else if (typeflag & FILE_TYPE_BLENDERLIB) { @@ -1952,6 +1954,9 @@ int ED_path_extension_type(const char *path) else if (BLI_testextensie(path, ".dae")) { return FILE_TYPE_COLLADA; } + else if (BLI_testextensie(path, ".abc")) { + return FILE_TYPE_ALEMBIC; + } else if (BLI_testextensie_array(path, imb_ext_image) || (G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt))) { @@ -2004,6 +2009,8 @@ int ED_file_extension_icon(const char *path) return ICON_FILE_BLANK; case FILE_TYPE_COLLADA: return ICON_FILE_BLANK; + case FILE_TYPE_ALEMBIC: + return ICON_FILE_BLANK; case FILE_TYPE_TEXT: return ICON_FILE_TEXT; default: diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index ab33d452d3c..1a558d40560 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -185,6 +185,8 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BTX : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_collada"))) params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ALEMBIC : 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) { /* Protection against pyscripts not setting proper size limit... */ char *tmp = RNA_property_string_get_alloc( @@ -213,7 +215,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | - FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO; + FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF; if (U.uiflag & USER_HIDE_DOT) { params->flag |= FILE_HIDE_DOT; diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 9032d286933..3243579f7d0 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -131,6 +131,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ case ANIMTYPE_DSLAM: case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: case ANIMTYPE_DSCUR: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 9e73e03a664..4f30c049d9d 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -170,6 +170,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ case ANIMTYPE_DSLAM: case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: case ANIMTYPE_DSCUR: case ANIMTYPE_DSSKEY: case ANIMTYPE_DSWOR: diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index b57462df53b..d4553b650c5 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1173,6 +1173,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto UI_icon_draw(x, y, ICON_MOD_TRIANGULATE); break; case eModifierType_MeshCache: UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ + case eModifierType_MeshSequenceCache: + UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ case eModifierType_Wireframe: UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break; case eModifierType_LaplacianDeform: diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index d2666cd0b6d..ca037cb20cc 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -62,7 +62,7 @@ typedef struct TreeElement { #define TREESTORE_ID_TYPE(_id) \ (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \ ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \ - ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO)) /* Only in 'blendfile' mode ... :/ */ + ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF)) /* Only in 'blendfile' mode ... :/ */ /* TreeElement->flag */ #define TE_ACTIVE 1 diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index b22e6595caf..96bab3d5c1e 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -38,6 +38,7 @@ #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_camera_types.h" +#include "DNA_cachefile_types.h" #include "DNA_gpencil_types.h" #include "DNA_group_types.h" #include "DNA_key_types.h" @@ -746,6 +747,16 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0); break; } + case ID_CF: + { + CacheFile *cache_file = (CacheFile *)id; + + if (outliner_animdata_test(cache_file->adt)) { + outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0); + } + + break; + } case ID_LA: { Lamp *la = (Lamp *)id; diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 525d42a1965..021c4a54b0a 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -32,7 +32,10 @@ #include #include +#include "DNA_cachefile_types.h" +#include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -42,7 +45,10 @@ #include "BLI_dlrbTree.h" #include "BLI_utildefines.h" +#include "BKE_constraint.h" #include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_screen.h" #include "BKE_pointcache.h" @@ -320,6 +326,9 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) case ID_GD: gpencil_to_keylist(&ads, (bGPdata *)id, &keys); break; + case ID_CF: + cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL); + break; } /* build linked-list for searching */ @@ -344,6 +353,56 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) BLI_dlrbTree_free(&keys); } +static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel) +{ + CacheFile *cache_file; + + for (cache_file = bmain->cachefiles.first; + cache_file; + cache_file = cache_file->id.next) + { + cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN; + } + + for (Base *base = scene->base.first; base; base = base->next) { + Object *ob = base->object; + + ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); + + if (md) { + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + + cache_file = mcmd->cache_file; + + if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) { + continue; + } + + cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN; + + time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel); + } + + for (bConstraint *con = ob->constraints.first; con; con = con->next) { + if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { + continue; + } + + bTransformCacheConstraint *data = con->data; + + cache_file = data->cache_file; + + if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) { + continue; + } + + cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN; + + time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel); + } + } +} + /* draw keyframe lines for timeline */ static void time_draw_keyframes(const bContext *C, ARegion *ar) { @@ -354,7 +413,11 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar) /* set this for all keyframe lines once and for all */ glLineWidth(1.0); - + + /* draw cache files keyframes (if available) */ + UI_ThemeColor(TH_TIME_KEYFRAME); + time_draw_caches_keyframes(CTX_data_main(C), scene, v2d, onlysel); + /* draw grease pencil keyframes (if available) */ UI_ThemeColor(TH_TIME_GP_KEYFRAME); if (scene->gpd) { -- cgit v1.2.3