/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** \file * \ingroup modifiers */ #include "DNA_cachefile_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_cachefile.h" #include "BKE_library_query.h" #include "BKE_scene.h" #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" #include "MOD_modifiertypes.h" #ifdef WITH_ALEMBIC # include "ABC_alembic.h" # include "BKE_global.h" # include "BKE_library.h" #endif static void initData(ModifierData *md) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; mcmd->cache_file = NULL; mcmd->object_path[0] = '\0'; mcmd->read_flag = MOD_MESHSEQ_READ_ALL; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { #if 0 const MeshSeqCacheModifierData *mcmd = (const MeshSeqCacheModifierData *)md; #endif MeshSeqCacheModifierData *tmcmd = (MeshSeqCacheModifierData *)target; modifier_copyData_generic(md, target, flag); tmcmd->reader = NULL; } static void freeData(ModifierData *md) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; if (mcmd->reader) { #ifdef WITH_ALEMBIC CacheReader_free(mcmd->reader); #endif mcmd->reader = NULL; } } static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; /* leave it up to the modifier to check the file is valid on calculation */ return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0'); } static Mesh *applyModifier( ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { #ifdef WITH_ALEMBIC MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; /* Only used to check whether we are operating on org data or not... */ Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL; Mesh *org_mesh = mesh; Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); const float frame = DEG_get_ctime(ctx->depsgraph); const float time = BKE_cachefile_time_offset(mcmd->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) { modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath); return mesh; } } if (me != NULL) { MVert *mvert = mesh->mvert; MEdge *medge = mesh->medge; MPoly *mpoly = mesh->mpoly; if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) { /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */ BKE_id_copy_ex(NULL, &mesh->id, (ID **)&mesh, LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW); } } Mesh *result = ABC_read_mesh(mcmd->reader, ctx->object, mesh, time, &err_str, mcmd->read_flag); if (err_str) { modifier_setError(md, "%s", err_str); } if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) { BKE_id_free(NULL, mesh); mesh = org_mesh; } return result ? result : mesh; #else UNUSED_VARS(ctx, md); return mesh; #endif } static bool dependsOnTime(ModifierData *md) { #ifdef WITH_ALEMBIC MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; return (mcmd->cache_file != NULL); #else UNUSED_VARS(md); return false; #endif } static void foreachIDLink( ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; if (mcmd->cache_file != NULL) { DEG_add_object_cache_relation(ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File"); } } ModifierTypeInfo modifierType_MeshSequenceCache = { /* name */ "Mesh Sequence Cache", /* structName */ "MeshSeqCacheModifierData", /* structSize */ sizeof(MeshSeqCacheModifierData), /* type */ eModifierTypeType_Constructive, /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs, /* copyData */ copyData, /* deformVerts_DM */ NULL, /* deformMatrices_DM */ NULL, /* deformVertsEM_DM */ NULL, /* deformMatricesEM_DM*/NULL, /* applyModifier_DM */ NULL, /* deformVerts */ NULL, /* deformMatrices */ NULL, /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* applyModifier */ applyModifier, /* initData */ initData, /* requiredDataMask */ NULL, /* freeData */ freeData, /* isDisabled */ isDisabled, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, /* foreachObjectLink */ NULL, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, /* freeRuntimeData */ NULL, };