diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2016-08-06 13:25:24 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2016-08-06 13:45:03 +0300 |
commit | 9843921288307be33fc39450586ff9ad226829a1 (patch) | |
tree | de6e0ddd71b48d036bf5525e62edf10a57d3238e /source/blender/blenkernel/intern | |
parent | 4571fdde0ecfdebac6a9374364b05be74233aca5 (diff) | |
parent | 28c3bdf50bd62b510fdbd88a5dcb1c40f8726c20 (diff) |
Merge branch 'master' into blender2.8
Conflicts:
release/scripts/startup/bl_ui/properties_particle.py
release/scripts/startup/bl_ui/properties_physics_cloth.py
release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
release/scripts/startup/bl_ui/properties_physics_softbody.py
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/cloth.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/library_query.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/versioning_270.c
source/blender/editors/space_file/filesel.c
source/blender/editors/space_outliner/outliner_intern.h
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_object_force.h
source/blender/makesdna/DNA_particle_types.h
source/blender/makesrna/intern/rna_particle.c
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/makesrna/intern/rna_smoke.c
source/blender/makesrna/intern/rna_space.c
Diffstat (limited to 'source/blender/blenkernel/intern')
26 files changed, 1885 insertions, 408 deletions
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index fa156e95d46..7ad2b118e72 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -96,6 +96,7 @@ bool id_type_can_have_animdata(const short id_type) case ID_MC: case ID_MSK: case ID_GD: + case ID_CF: return true; /* no AnimData */ @@ -1156,6 +1157,9 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u /* grease pencil */ ANIMDATA_IDS_CB(mainptr->gpencil.first); + + /* cache files */ + ANIMDATA_IDS_CB(mainptr->cachefiles.first); } /* Fix all RNA-Paths throughout the database (directly access the Global.main version) @@ -1243,6 +1247,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha /* grease pencil */ RENAMEFIX_ANIM_IDS(mainptr->gpencil.first); + + /* cache files */ + RENAMEFIX_ANIM_IDS(mainptr->cachefiles.first); /* scenes */ RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene); @@ -1475,161 +1482,193 @@ static bool animsys_remap_path(AnimMapper *UNUSED(remap), char *path, char **dst return false; } +static bool animsys_store_rna_setting( + PointerRNA *ptr, AnimMapper *remap, + /* typically 'fcu->rna_path', 'fcu->array_index' */ + const char *rna_path, const int array_index, + PathResolvedRNA *r_result) +{ + bool success = false; + + char *path = NULL; + bool free_path; + + /* get path, remapped as appropriate to work in its new environment */ + free_path = animsys_remap_path(remap, (char *)rna_path, &path); + + /* write value to setting */ + if (path) { + /* get property to write to */ + if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) { + if ((ptr->id.data == NULL) || RNA_property_animateable(&r_result->ptr, r_result->prop)) { + int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop); + + if (array_len && array_index >= array_len) { + if (G.debug & G_DEBUG) { + printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n", + (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", + path, array_index, array_len - 1); + } + } + else { + r_result->prop_index = array_len ? array_index : -1; + success = true; + } + } + } + else { + /* failed to get path */ + /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) + * where some channels will not exist, but shouldn't lock up Action */ + if (G.debug & G_DEBUG) { + printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n", + (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", + path, array_index); + } + } + } + + /* free temp path-info */ + if (free_path) { + MEM_freeN((void *)path); + } + + return success; +} + /* less than 1.0 evaluates to false, use epsilon to avoid float error */ #define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON))) /* Write the given value to a setting using RNA, and return success */ -static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_index, float value) +static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value) { - PropertyRNA *prop; - PointerRNA new_ptr; + PropertyRNA *prop = anim_rna->prop; + PointerRNA *ptr = &anim_rna->ptr; + int array_index = anim_rna->prop_index; - //printf("%p %s %i %f\n", ptr, path, array_index, value); - - /* get property to write to */ - if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop)) { - /* set value for animatable numerical values only - * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated - * without an ID provided, which causes the animateable test to fail! - */ - if (RNA_property_animateable(&new_ptr, prop) || (ptr->id.data == NULL)) { - int array_len = RNA_property_array_length(&new_ptr, prop); - bool written = false; - - if (array_len && array_index >= array_len) { - if (G.debug & G_DEBUG) { - printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d\n", - (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", - path, array_index, array_len - 1); + /* caller must ensure this is animatable */ + BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL); + + /* set value for animatable numerical values only + * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated + * without an ID provided, which causes the animateable test to fail! + */ + bool written = false; + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + { + const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value); + if (array_index != -1) { + if (RNA_property_boolean_get_index(ptr, prop, array_index) != value_coerce) { + RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce); + written = true; } - - return false; } - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - if (array_len) { - if (RNA_property_boolean_get_index(&new_ptr, prop, array_index) != ANIMSYS_FLOAT_AS_BOOL(value)) { - RNA_property_boolean_set_index(&new_ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value)); - written = true; - } - } - else { - if (RNA_property_boolean_get(&new_ptr, prop) != ANIMSYS_FLOAT_AS_BOOL(value)) { - RNA_property_boolean_set(&new_ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value)); - written = true; - } - } - break; - case PROP_INT: - if (array_len) { - if (RNA_property_int_get_index(&new_ptr, prop, array_index) != (int)value) { - RNA_property_int_set_index(&new_ptr, prop, array_index, (int)value); - written = true; - } - } - else { - if (RNA_property_int_get(&new_ptr, prop) != (int)value) { - RNA_property_int_set(&new_ptr, prop, (int)value); - written = true; - } - } - break; - case PROP_FLOAT: - if (array_len) { - if (RNA_property_float_get_index(&new_ptr, prop, array_index) != value) { - RNA_property_float_set_index(&new_ptr, prop, array_index, value); - written = true; - } - } - else { - if (RNA_property_float_get(&new_ptr, prop) != value) { - RNA_property_float_set(&new_ptr, prop, value); - written = true; - } - } - break; - case PROP_ENUM: - if (RNA_property_enum_get(&new_ptr, prop) != (int)value) { - RNA_property_enum_set(&new_ptr, prop, (int)value); - written = true; - } - break; - default: - /* nothing can be done here... so it is unsuccessful? */ - return false; + else { + if (RNA_property_boolean_get(ptr, prop) != value_coerce) { + RNA_property_boolean_set(ptr, prop, value_coerce); + written = true; + } } - - /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */ -#if 0 - /* buffer property update for later flushing */ - if (written && RNA_property_update_check(prop)) { - short skip_updates_hack = 0; - - /* optimization hacks: skip property updates for those properties - * for we know that which the updates in RNA were really just for - * flushing property editing via UI/Py - */ - if (new_ptr.type == &RNA_PoseBone) { - /* bone transforms - update pose (i.e. tag depsgraph) */ - skip_updates_hack = 1; + break; + } + case PROP_INT: + { + const int value_coerce = (int)value; + if (array_index != -1) { + if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) { + RNA_property_int_set_index(ptr, prop, array_index, value_coerce); + written = true; } - - if (skip_updates_hack == 0) - RNA_property_update_cache_add(&new_ptr, prop); } -#endif - - /* as long as we don't do property update, we still tag datablock - * as having been updated. this flag does not cause any updates to - * be run, it's for e.g. render engines to synchronize data */ - if (written && new_ptr.id.data) { - ID *id = new_ptr.id.data; - - /* for cases like duplifarmes it's only a temporary so don't - * notify anyone of updates */ - if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) { - id->tag |= LIB_TAG_ID_RECALC; - DAG_id_type_tag(G.main, GS(id->name)); + else { + if (RNA_property_int_get(ptr, prop) != value_coerce) { + RNA_property_int_set(ptr, prop, value_coerce); + written = true; } } + break; } - - /* successful */ - return true; + case PROP_FLOAT: + { + if (array_index != -1) { + if (RNA_property_float_get_index(ptr, prop, array_index) != value) { + RNA_property_float_set_index(ptr, prop, array_index, value); + written = true; + } + } + else { + if (RNA_property_float_get(ptr, prop) != value) { + RNA_property_float_set(ptr, prop, value); + written = true; + } + } + break; + } + case PROP_ENUM: + { + const int value_coerce = (int)value; + if (RNA_property_enum_get(ptr, prop) != value_coerce) { + RNA_property_enum_set(ptr, prop, value_coerce); + written = true; + } + break; + } + default: + /* nothing can be done here... so it is unsuccessful? */ + return false; } - else { - /* failed to get path */ - /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) - * where some channels will not exist, but shouldn't lock up Action */ - if (G.debug & G_DEBUG) { - printf("Animato: Invalid path. ID = '%s', '%s[%d]'\n", - (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", - path, array_index); + + /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */ +#if 0 + /* buffer property update for later flushing */ + if (written && RNA_property_update_check(prop)) { + short skip_updates_hack = 0; + + /* optimization hacks: skip property updates for those properties + * for we know that which the updates in RNA were really just for + * flushing property editing via UI/Py + */ + if (new_ptr.type == &RNA_PoseBone) { + /* bone transforms - update pose (i.e. tag depsgraph) */ + skip_updates_hack = 1; + } + + if (skip_updates_hack == 0) + RNA_property_update_cache_add(ptr, prop); + } +#endif + + /* as long as we don't do property update, we still tag datablock + * as having been updated. this flag does not cause any updates to + * be run, it's for e.g. render engines to synchronize data */ + if (written && ptr->id.data) { + ID *id = ptr->id.data; + + /* for cases like duplifarmes it's only a temporary so don't + * notify anyone of updates */ + if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) { + id->tag |= LIB_TAG_ID_RECALC; + DAG_id_type_tag(G.main, GS(id->name)); } - return false; } + + /* successful */ + return true; } /* Simple replacement based data-setting of the FCurve using RNA */ bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, float curval) { - char *path = NULL; - bool free_path = false; + PathResolvedRNA anim_rna; bool ok = false; - - /* get path, remapped as appropriate to work in its new environment */ - free_path = animsys_remap_path(remap, fcu->rna_path, &path); - - /* write value to setting */ - if (path) - ok = animsys_write_rna_setting(ptr, path, fcu->array_index, curval); - - /* free temp path-info */ - if (free_path) - MEM_freeN(path); - + + if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { + ok = animsys_write_rna_setting(&anim_rna, curval); + } + /* return whether we were successful */ return ok; } @@ -1647,8 +1686,11 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) { /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { - const float curval = calculate_fcurve(fcu, ctime); - BKE_animsys_execute_fcurve(ptr, remap, fcu, curval); + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + animsys_write_rna_setting(&anim_rna, curval); + } } } } @@ -1677,8 +1719,12 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime /* evaluate this using values set already in other places * NOTE: for 'layering' option later on, we should check if we should remove old value before adding * new to only be done when drivers only changed */ - const float curval = calculate_fcurve(fcu, ctime); - ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu, curval); + + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + ok = animsys_write_rna_setting(&anim_rna, curval); + } /* clear recalc flag */ driver->flag &= ~DRIVER_FLAG_RECALC; @@ -1746,8 +1792,11 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) { /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { - const float curval = calculate_fcurve(fcu, ctime); - BKE_animsys_execute_fcurve(ptr, remap, fcu, curval); + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + animsys_write_rna_setting(&anim_rna, curval); + } } } } @@ -2605,8 +2654,12 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) AnimOverride *aor; /* for each override, simply execute... */ - for (aor = adt->overrides.first; aor; aor = aor->next) - animsys_write_rna_setting(ptr, aor->rna_path, aor->array_index, aor->value); + for (aor = adt->overrides.first; aor; aor = aor->next) { + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, NULL, aor->rna_path, aor->array_index, &anim_rna)) { + animsys_write_rna_setting(&anim_rna, aor->value); + } + } } /* ***************************************** */ @@ -2817,6 +2870,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) /* grease pencil */ EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM); + + /* cache files */ + EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM); /* objects */ /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets @@ -2878,8 +2934,13 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx, * NOTE: for 'layering' option later on, we should check if we should remove old value before adding * new to only be done when drivers only changed */ //printf("\told val = %f\n", fcu->curval); - const float curval = calculate_fcurve(fcu, eval_ctx->ctime); - ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu, curval); + + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(&id_ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, eval_ctx->ctime); + ok = animsys_write_rna_setting(&anim_rna, curval); + } + //printf("\tnew val = %f\n", fcu->curval); /* clear recalc flag */ diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index f3ff0f253e5..4121bde4d0b 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -48,6 +48,7 @@ #include "MEM_guardedalloc.h" #include "DNA_brush_types.h" +#include "DNA_cachefile_types.h" #include "DNA_image_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" @@ -618,6 +619,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data); break; } + case ID_CF: + { + CacheFile *cache_file = (CacheFile *)id; + rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data); + break; + } default: /* Nothing to do for other IDs that don't contain file paths. */ break; diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c new file mode 100644 index 00000000000..16f263791db --- /dev/null +++ b/source/blender/blenkernel/intern/cachefile.c @@ -0,0 +1,173 @@ +/* + * ***** 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. + * + * Contributor(s): Kevin Dietrich. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/cachefile.c + * \ingroup bke + */ + +#include "DNA_anim_types.h" +#include "DNA_cachefile_types.h" +#include "DNA_scene_types.h" + +#include "BLI_fileops.h" +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_animsys.h" +#include "BKE_cachefile.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#ifdef WITH_ALEMBIC +# include "ABC_alembic.h" +#endif + +void *BKE_cachefile_add(Main *bmain, const char *name) +{ + CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name); + + BKE_cachefile_init(cache_file); + + return cache_file; +} + +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; +} + +/** 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); + +#ifdef WITH_ALEMBIC + ABC_free_handle(cache_file->handle); +#endif + + BLI_freelistN(&cache_file->object_paths); +} + +CacheFile *BKE_cachefile_copy(Main *bmain, CacheFile *cache_file) +{ + CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id); + new_cache_file->handle = NULL; + + BLI_listbase_clear(&cache_file->object_paths); + + BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id); + + return new_cache_file; +} + +void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local); +} + +void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file) +{ + 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); + } + + cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths); +#endif +} + +void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file) +{ + if (cache_file->handle == NULL) { + BKE_cachefile_reload(bmain, cache_file); + } +} + +void BKE_cachefile_update_frame(Main *bmain, 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) { + /* Execute drivers only, as animation has already been done. */ + BKE_animsys_evaluate_animdata(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)) { +#ifdef WITH_ALEMBIC + ABC_free_handle(cache_file->handle); + cache_file->handle = ABC_create_handle(filename, NULL); +#endif + } + } +} + +bool BKE_cachefile_filepath_get( + const Main *bmain, const CacheFile *cache_file, float frame, + char r_filepath[FILE_MAX]) +{ + BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX); + BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id)); + + int fframe; + int frame_len; + + if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) { + char ext[32]; + BLI_path_frame_strip(r_filepath, true, ext); + BLI_path_frame(r_filepath, frame, frame_len); + BLI_ensure_extension(r_filepath, FILE_MAX, ext); + + /* TODO(kevin): store sequence range? */ + return BLI_exists(r_filepath); + } + + return true; +} + +float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps) +{ + const float frame = (cache_file->override_frame ? cache_file->frame : time); + return cache_file->is_sequence ? frame : frame / fps; +} diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 159d5b82a6c..d257a1cfcae 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -3402,7 +3402,7 @@ void CDDM_calc_edges(DerivedMesh *dm) BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2); j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi)); - if (j == 0) { + if (j == 0 || !eindex) { med->flag = ME_EDGEDRAW | ME_EDGERENDER; *index = ORIGINDEX_NONE; } diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index fa0960515b4..4ab6c82b2c2 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -57,6 +57,7 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm ); static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first); static void cloth_update_springs( ClothModifierData *clmd ); +static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ); static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm ); static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ); static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ); @@ -95,6 +96,7 @@ void cloth_init(ClothModifierData *clmd ) clmd->sim_parms->avg_spring_len = 0.0; clmd->sim_parms->presets = 2; /* cotton as start setting */ clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */ + clmd->sim_parms->time_scale = 1.0f; /* multiplies cloth speed */ clmd->sim_parms->reset = 0; clmd->sim_parms->vel_damping = 1.0f; /* 1.0 = no damping, 0.0 = fully dampened */ @@ -345,10 +347,13 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul effectors = pdInitEffectors(clmd->scene, ob, clmd->sim_parms->effector_weights, true); + if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) + cloth_update_verts ( ob, clmd, result ); + /* Support for dynamic vertex groups, changing from frame to frame */ cloth_apply_vgroup ( clmd, result ); - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) + if ( clmd->sim_parms->flags & (CLOTH_SIMSETTINGS_FLAG_SEW | CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) ) cloth_update_spring_lengths ( clmd, result ); cloth_update_springs( clmd ); @@ -376,7 +381,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived clmd->scene= scene; /* nice to pass on later :) */ - clmd->sim_parms->timescale= 1.0f; + clmd->sim_parms->timescale = 1.0f; if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->mvert_num)) { clmd->sim_parms->reset = 0; @@ -729,7 +734,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d clmd->clothObject->springs = NULL; clmd->clothObject->numsprings = -1; - if ( clmd->sim_parms->shapekey_rest ) + if ( clmd->sim_parms->shapekey_rest && !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) ) shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO ); mvert = dm->getVertArray (dm); @@ -1105,6 +1110,20 @@ static void cloth_update_springs( ClothModifierData *clmd ) cloth_hair_update_bending_targets(clmd); } +/* Update rest verts, for dynamically deformable cloth */ +static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ) +{ + unsigned int i = 0; + MVert *mvert = dm->getVertArray (dm); + ClothVertex *verts = clmd->clothObject->verts; + + /* vertex count is already ensured to match */ + for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) { + copy_v3_v3(verts->xrest, mvert[i].co); + mul_m4_v3(ob->obmat, verts->xrest); + } +} + /* Update spring rest lenght, for dynamically deformable cloth */ static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm ) { diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 53a74024c51..4f3ffed41bc 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -293,8 +293,8 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope) cuma->curve[1].x = clipr->xmax; cuma->curve[1].y = clipr->ymin; if (slope == CURVEMAP_SLOPE_POS_NEG) { - cuma->curve[0].flag |= CUMA_VECTOR; - cuma->curve[1].flag |= CUMA_VECTOR; + cuma->curve[0].flag |= CUMA_HANDLE_VECTOR; + cuma->curve[1].flag |= CUMA_HANDLE_VECTOR; } break; case CURVE_PRESET_SHARP: @@ -391,15 +391,25 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope) } } -/* if type==1: vector, else auto */ -void curvemap_sethandle(CurveMap *cuma, int type) +/** + * \param type: eBezTriple_Handle + */ +void curvemap_handle_set(CurveMap *cuma, int type) { int a; for (a = 0; a < cuma->totpoint; a++) { if (cuma->curve[a].flag & CUMA_SELECT) { - if (type) cuma->curve[a].flag |= CUMA_VECTOR; - else cuma->curve[a].flag &= ~CUMA_VECTOR; + cuma->curve[a].flag &= ~(CUMA_HANDLE_VECTOR | CUMA_HANDLE_AUTO_ANIM); + if (type == HD_VECT) { + cuma->curve[a].flag |= CUMA_HANDLE_VECTOR; + } + else if (type == HD_AUTO_ANIM) { + cuma->curve[a].flag |= CUMA_HANDLE_AUTO_ANIM; + } + else { + /* pass */ + } } } } @@ -457,7 +467,7 @@ static void calchandle_curvemap( if (len_a == 0.0f) len_a = 1.0f; if (len_b == 0.0f) len_b = 1.0f; - if (bezt->h1 == HD_AUTO || bezt->h2 == HD_AUTO) { /* auto */ + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */ float tvec[2]; tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a; tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a; @@ -465,13 +475,57 @@ static void calchandle_curvemap( len = len_v2(tvec) * 2.5614f; if (len != 0.0f) { - if (bezt->h1 == HD_AUTO) { + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { len_a /= len; madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a); + + if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ + const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1]; + const float ydiff2 = next->vec[1][1] - bezt->vec[1][1]; + if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || + (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) + { + bezt->vec[0][1] = bezt->vec[1][1]; + } + else { /* handles should not be beyond y coord of two others */ + if (ydiff1 <= 0.0f) { + if (prev->vec[1][1] > bezt->vec[0][1]) { + bezt->vec[0][1] = prev->vec[1][1]; + } + } + else { + if (prev->vec[1][1] < bezt->vec[0][1]) { + bezt->vec[0][1] = prev->vec[1][1]; + } + } + } + } } - if (bezt->h2 == HD_AUTO) { + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { len_b /= len; madd_v2_v2v2fl(p2_h2, p2, tvec, len_b); + + if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ + const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1]; + const float ydiff2 = next->vec[1][1] - bezt->vec[1][1]; + if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f)|| + (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) + { + bezt->vec[2][1] = bezt->vec[1][1]; + } + else { /* handles should not be beyond y coord of two others */ + if (ydiff1 <= 0.0f) { + if (next->vec[1][1] < bezt->vec[2][1]) { + bezt->vec[2][1] = next->vec[1][1]; + } + } + else { + if (next->vec[1][1] > bezt->vec[2][1]) { + bezt->vec[2][1] = next->vec[1][1]; + } + } + } + } } } } @@ -540,10 +594,15 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x); bezt[a].vec[1][0] = cmp[a].x; bezt[a].vec[1][1] = cmp[a].y; - if (cmp[a].flag & CUMA_VECTOR) + if (cmp[a].flag & CUMA_HANDLE_VECTOR) { bezt[a].h1 = bezt[a].h2 = HD_VECT; - else + } + else if (cmp[a].flag & CUMA_HANDLE_AUTO_ANIM) { + bezt[a].h1 = bezt[a].h2 = HD_AUTO_ANIM; + } + else { bezt[a].h1 = bezt[a].h2 = HD_AUTO; + } } const BezTriple *bezt_prev = NULL; @@ -773,12 +832,12 @@ void curvemapping_changed(CurveMapping *cumap, const bool rem_doubles) dy = cmp[a].y - cmp[a + 1].y; if (sqrtf(dx * dx + dy * dy) < thresh) { if (a == 0) { - cmp[a + 1].flag |= CUMA_VECTOR; + cmp[a + 1].flag |= CUMA_HANDLE_VECTOR; if (cmp[a + 1].flag & CUMA_SELECT) cmp[a].flag |= CUMA_SELECT; } else { - cmp[a].flag |= CUMA_VECTOR; + cmp[a].flag |= CUMA_HANDLE_VECTOR; if (cmp[a].flag & CUMA_SELECT) cmp[a + 1].flag |= CUMA_SELECT; } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 4c9ddd495e3..70fdd4aa72e 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -46,6 +46,7 @@ #include "BLT_translation.h" #include "DNA_armature_types.h" +#include "DNA_cachefile_types.h" #include "DNA_constraint_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -63,6 +64,7 @@ #include "BKE_anim.h" /* for the curve calculation part */ #include "BKE_armature.h" #include "BKE_bvhutils.h" +#include "BKE_cachefile.h" #include "BKE_camera.h" #include "BKE_constraint.h" #include "BKE_curve.h" @@ -86,6 +88,10 @@ # include "BPY_extern.h" #endif +#ifdef WITH_ALEMBIC +# include "ABC_alembic.h" +#endif + /* ---------------------------------------------------------------------------- */ /* Useful macros for testing various common flag combinations */ @@ -4333,6 +4339,73 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = { objectsolver_evaluate /* evaluate */ }; +/* ----------- Transform Cache ------------- */ + +static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) +{ + bTransformCacheConstraint *data = con->data; + func(con, (ID **)&data->cache_file, false, userdata); +} + +static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ +#ifdef WITH_ALEMBIC + bTransformCacheConstraint *data = con->data; + Scene *scene = cob->scene; + + const float frame = BKE_scene_frame_get(scene); + const float time = BKE_cachefile_time_offset(data->cache_file, frame, FPS); + + CacheFile *cache_file = data->cache_file; + + BKE_cachefile_ensure_handle(G.main, cache_file); + + ABC_get_transform(cache_file->handle, cob->ob, data->object_path, + cob->matrix, time, cache_file->scale); +#else + UNUSED_VARS(con, cob); +#endif + + UNUSED_VARS(targets); +} + +static void transformcache_copy(bConstraint *con, bConstraint *srccon) +{ + bTransformCacheConstraint *src = srccon->data; + bTransformCacheConstraint *dst = con->data; + + BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path)); + dst->cache_file = src->cache_file; + + if (dst->cache_file) { + id_us_plus(&dst->cache_file->id); + } +} + +static void transformcache_free(bConstraint *con) +{ + bTransformCacheConstraint *data = con->data; + + if (data->cache_file) { + id_us_min(&data->cache_file->id); + } +} + +static bConstraintTypeInfo CTI_TRANSFORM_CACHE = { + CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */ + sizeof(bTransformCacheConstraint), /* size */ + "Transform Cache", /* name */ + "bTransformCacheConstraint", /* struct name */ + transformcache_free, /* free data */ + transformcache_id_looper, /* id looper */ + transformcache_copy, /* copy data */ + NULL, /* new data */ + NULL, /* get constraint targets */ + NULL, /* flush constraint targets */ + NULL, /* get target matrix */ + transformcache_evaluate /* evaluate */ +}; + /* ************************* Constraints Type-Info *************************** */ /* All of the constraints api functions use bConstraintTypeInfo structs to carry out * and operations that involve constraint specific code. @@ -4374,6 +4447,7 @@ static void constraints_init_typeinfo(void) constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */ constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */ constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */ + constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */ } /* This function should be used for getting the appropriate type-info when only diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 43612c877ea..f7268a91310 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -1066,6 +1066,11 @@ struct EditBone *CTX_data_active_bone(const bContext *C) return ctx_data_pointer_get(C, "active_bone"); } +struct CacheFile *CTX_data_edit_cachefile(const bContext *C) +{ + return ctx_data_pointer_get(C, "edit_cachefile"); +} + int CTX_data_selected_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_bones", list); @@ -1111,6 +1116,21 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C) return ctx_data_pointer_get(C, "active_gpencil_layer"); } +bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_gpencil_palette"); +} + +bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_gpencil_palettecolor"); +} + +bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_gpencil_brush"); +} + bGPDframe *CTX_data_active_gpencil_frame(const bContext *C) { return ctx_data_pointer_get(C, "active_gpencil_frame"); diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index f06f7f55699..85ecf495805 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -46,6 +46,7 @@ #include "DNA_anim_types.h" #include "DNA_camera_types.h" +#include "DNA_cachefile_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_lattice_types.h" @@ -2019,7 +2020,12 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) if (cti) { /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { + if (ELEM(cti->type, + CONSTRAINT_TYPE_FOLLOWTRACK, + CONSTRAINT_TYPE_CAMERASOLVER, + CONSTRAINT_TYPE_OBJECTSOLVER, + CONSTRAINT_TYPE_TRANSFORM_CACHE)) + { ob->recalc |= OB_RECALC_OB; } else if (cti->get_constraint_targets) { @@ -2784,6 +2790,33 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) /* BLI_assert(!"invalid flag for this 'idtype'"); */ } } + else if (GS(id->name) == ID_CF) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); + + if (md) { + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + + if (mcmd->cache_file && (&mcmd->cache_file->id == id)) { + ob->recalc |= OB_RECALC_DATA; + continue; + } + } + + for (bConstraint *con = ob->constraints.first; con; con = con->next) { + if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { + continue; + } + + bTransformCacheConstraint *data = con->data; + + if (data->cache_file && (&data->cache_file->id == id)) { + ob->recalc |= OB_RECALC_DATA; + break; + } + } + } + } } void DAG_id_tag_update(ID *id, short flag) diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 395161aa6ed..a89d423e7a6 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1859,7 +1859,7 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) * - "evaltime" is the frame at which F-Curve is being evaluated * - has to return a float value */ -float evaluate_driver(ChannelDriver *driver, const float evaltime) +float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime) { DriverVar *dvar; @@ -1944,7 +1944,9 @@ float evaluate_driver(ChannelDriver *driver, const float evaltime) * - on errors it reports, then returns 0.0f */ BLI_mutex_lock(&python_driver_lock); - driver->curval = BPY_driver_exec(driver, evaltime); + + driver->curval = BPY_driver_exec(anim_rna, driver, evaltime); + BLI_mutex_unlock(&python_driver_lock); } #else /* WITH_PYTHON*/ @@ -2599,25 +2601,64 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) /* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime") * Note: this is also used for drivers */ -float evaluate_fcurve(FCurve *fcu, float evaltime) +static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue) { FModifierStackStorage *storage; - float cvalue = 0.0f; float devaltime; + + /* evaluate modifiers which modify time to evaluate the base curve at */ + storage = evaluate_fmodifiers_storage_new(&fcu->modifiers); + devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime); + + /* evaluate curve-data + * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying + * F-Curve modifier on the stack requested the curve to be evaluated at + */ + if (fcu->bezt) + cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime); + else if (fcu->fpt) + cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime); + + /* evaluate modifiers */ + evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime); + + evaluate_fmodifiers_storage_free(storage); + + /* if curve can only have integral values, perform truncation (i.e. drop the decimal part) + * here so that the curve can be sampled correctly + */ + if (fcu->flag & FCURVE_INT_VALUES) + cvalue = floorf(cvalue + 0.5f); - /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime" + /* return evaluated value */ + return cvalue; +} + +float evaluate_fcurve(FCurve *fcu, float evaltime) +{ + BLI_assert(fcu->driver == NULL); + + return evaluate_fcurve_ex(fcu, evaltime, 0.0); +} + +float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) +{ + BLI_assert(fcu->driver != NULL); + float cvalue = 0.0f; + + /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime" * since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves */ if (fcu->driver) { /* evaltime now serves as input for the curve */ - evaltime = evaluate_driver(fcu->driver, evaltime); - + evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime); + /* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */ if (fcu->totvert == 0) { FModifier *fcm; bool do_linear = true; - - /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values + + /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values * XXX: additive is a bit more dicey; it really depends then if things are in range or not... */ for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) { @@ -2634,7 +2675,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime) do_linear = false; } } - + /* only copy over results if none of the modifiers disagreed with this */ if (do_linear) { cvalue = evaltime; @@ -2642,36 +2683,11 @@ float evaluate_fcurve(FCurve *fcu, float evaltime) } } - /* evaluate modifiers which modify time to evaluate the base curve at */ - storage = evaluate_fmodifiers_storage_new(&fcu->modifiers); - devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime); - - /* evaluate curve-data - * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying - * F-Curve modifier on the stack requested the curve to be evaluated at - */ - if (fcu->bezt) - cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime); - else if (fcu->fpt) - cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime); - - /* evaluate modifiers */ - evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime); - - evaluate_fmodifiers_storage_free(storage); - - /* if curve can only have integral values, perform truncation (i.e. drop the decimal part) - * here so that the curve can be sampled correctly - */ - if (fcu->flag & FCURVE_INT_VALUES) - cvalue = floorf(cvalue + 0.5f); - - /* return evaluated value */ - return cvalue; + return evaluate_fcurve_ex(fcu, evaltime, cvalue); } /* Calculate the value of the given F-Curve at the given frame, and set its curval */ -float calculate_fcurve(FCurve *fcu, float evaltime) +float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) { /* only calculate + set curval (overriding the existing value) if curve has * any data which warrants this... @@ -2680,7 +2696,13 @@ float calculate_fcurve(FCurve *fcu, float evaltime) list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE)) { /* calculate and set curval (evaluates driver too if necessary) */ - float curval = evaluate_fcurve(fcu, evaltime); + float curval; + if (fcu->driver) { + curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime); + } + else { + curval = evaluate_fcurve(fcu, evaltime); + } fcu->curval = curval; /* debug display only, not thread safe! */ return curval; } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 8621da0d42e..e4bac0a947a 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -18,7 +18,7 @@ * The Original Code is Copyright (C) 2008, Blender Foundation * This is a new part of Blender * - * Contributor(s): Joshua Leung + * Contributor(s): Joshua Leung, Antonio Vazquez * * ***** END GPL LICENSE BLOCK ***** */ @@ -44,10 +44,12 @@ #include "DNA_gpencil_types.h" #include "DNA_userdef_types.h" +#include "DNA_scene_types.h" #include "BKE_animsys.h" #include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_colortools.h" #include "BKE_library.h" #include "BKE_main.h" @@ -57,76 +59,155 @@ /* --------- Memory Management ------------ */ +/* free stroke, doesn't unlink from any listbase */ +void BKE_gpencil_free_stroke(bGPDstroke *gps) +{ + if (gps == NULL) { + return; + } + + /* free stroke memory arrays, then stroke itself */ + if (gps->points) + MEM_freeN(gps->points); + if (gps->triangles) + MEM_freeN(gps->triangles); + + MEM_freeN(gps); +} + /* Free strokes belonging to a gp-frame */ -bool free_gpencil_strokes(bGPDframe *gpf) +bool BKE_gpencil_free_strokes(bGPDframe *gpf) { - bGPDstroke *gps, *gpsn; + bGPDstroke *gps_next; bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false); /* free strokes */ - for (gps = gpf->strokes.first; gps; gps = gpsn) { - gpsn = gps->next; - - /* free stroke memory arrays, then stroke itself */ - if (gps->points) MEM_freeN(gps->points); - if (gps->triangles) MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps_next) { + gps_next = gps->next; + BKE_gpencil_free_stroke(gps); } + BLI_listbase_clear(&gpf->strokes); return changed; } /* Free all of a gp-layer's frames */ -void free_gpencil_frames(bGPDlayer *gpl) +void BKE_gpencil_free_frames(bGPDlayer *gpl) { - bGPDframe *gpf, *gpfn; + bGPDframe *gpf_next; /* error checking */ if (gpl == NULL) return; /* free frames */ - for (gpf = gpl->frames.first; gpf; gpf = gpfn) { - gpfn = gpf->next; + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf_next) { + gpf_next = gpf->next; /* free strokes and their associated memory */ - free_gpencil_strokes(gpf); + BKE_gpencil_free_strokes(gpf); BLI_freelinkN(&gpl->frames, gpf); } gpl->actframe = NULL; } +/* Free all of a gp-colors */ +static void free_gpencil_colors(bGPDpalette *palette) +{ + /* error checking */ + if (palette == NULL) { + return; + } + + /* free colors */ + BLI_freelistN(&palette->colors); +} + +/* Free all of the gp-palettes and colors */ +void BKE_gpencil_free_palettes(ListBase *list) +{ + bGPDpalette *palette_next; + + /* error checking */ + if (list == NULL) { + return; + } + + /* delete palettes */ + for (bGPDpalette *palette = list->first; palette; palette = palette_next) { + palette_next = palette->next; + /* free palette colors */ + free_gpencil_colors(palette); + + MEM_freeN(palette); + } + BLI_listbase_clear(list); +} + +/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */ +void BKE_gpencil_free_brushes(ListBase *list) +{ + bGPDbrush *brush_next; + + /* error checking */ + if (list == NULL) { + return; + } + + /* delete brushes */ + for (bGPDbrush *brush = list->first; brush; brush = brush_next) { + brush_next = brush->next; + /* free curves */ + if (brush->cur_sensitivity) { + curvemapping_free(brush->cur_sensitivity); + } + if (brush->cur_strength) { + curvemapping_free(brush->cur_strength); + } + if (brush->cur_jitter) { + curvemapping_free(brush->cur_jitter); + } + + MEM_freeN(brush); + } + BLI_listbase_clear(list); +} + /* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */ -void free_gpencil_layers(ListBase *list) +void BKE_gpencil_free_layers(ListBase *list) { - bGPDlayer *gpl, *gpln; + bGPDlayer *gpl_next; /* error checking */ if (list == NULL) return; /* delete layers */ - for (gpl = list->first; gpl; gpl = gpln) { - gpln = gpl->next; + for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) { + gpl_next = gpl->next; /* free layers and their data */ - free_gpencil_frames(gpl); + BKE_gpencil_free_frames(gpl); BLI_freelinkN(list, gpl); } } -/* Free all of GPencil datablock's related data, but not the block itself */ /** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ -void BKE_gpencil_free(bGPdata *gpd) +void BKE_gpencil_free(bGPdata *gpd, bool free_palettes) { BKE_animdata_free(&gpd->id, false); /* free layers */ - free_gpencil_layers(&gpd->layers); + BKE_gpencil_free_layers(&gpd->layers); + + /* free palettes */ + if (free_palettes) { + BKE_gpencil_free_palettes(&gpd->palettes); + } } /* -------- Container Creation ---------- */ /* add a new gp-frame to the given layer */ -bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe) +bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe) { bGPDframe *gpf = NULL, *gf = NULL; short state = 0; @@ -178,9 +259,9 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe) } /* add a copy of the active gp-frame to the given layer */ -bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) +bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) { - bGPDframe *new_frame, *gpf; + bGPDframe *new_frame; bool found = false; /* Error checking/handling */ @@ -190,14 +271,14 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) } else if (gpl->actframe == NULL) { /* no active frame, so just create a new one from scratch */ - return gpencil_frame_addnew(gpl, cframe); + return BKE_gpencil_frame_addnew(gpl, cframe); } /* Create a copy of the frame */ - new_frame = gpencil_frame_duplicate(gpl->actframe); + new_frame = BKE_gpencil_frame_duplicate(gpl->actframe); /* Find frame to insert it before */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { if (gpf->framenum > cframe) { /* Add it here */ BLI_insertlinkbefore(&gpl->frames, gpf, new_frame); @@ -209,7 +290,7 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) /* This only happens when we're editing with framelock on... * - Delete the new frame and don't do anything else here... */ - free_gpencil_strokes(new_frame); + BKE_gpencil_free_strokes(new_frame); MEM_freeN(new_frame); new_frame = NULL; @@ -233,7 +314,7 @@ bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) } /* add a new gp-layer and make it the active layer */ -bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive) +bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive) { bGPDlayer *gpl; @@ -249,8 +330,11 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive) /* set basic settings */ copy_v4_v4(gpl->color, U.gpencil_new_layer_col); - gpl->thickness = 3; - + /* Since GPv2 thickness must be 0 */ + gpl->thickness = 0; + + gpl->opacity = 1.0f; + /* onion-skinning settings */ if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) gpl->flag |= GP_LAYER_ONIONSKIN; @@ -263,23 +347,280 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive) /* high quality fill by default */ gpl->flag |= GP_LAYER_HQ_FILL; - /* default smooth iterations */ - gpl->draw_smoothlvl = 1; - /* auto-name */ BLI_strncpy(gpl->info, name, sizeof(gpl->info)); BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); /* make this one the active one */ if (setactive) - gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_setactive(gpd, gpl); /* return layer */ return gpl; } +/* add a new gp-palette and make it the active */ +bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive) +{ + bGPDpalette *palette; + + /* check that list is ok */ + if (gpd == NULL) { + return NULL; + } + + /* allocate memory and add to end of list */ + palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette"); + + /* add to datablock */ + BLI_addtail(&gpd->palettes, palette); + + /* set basic settings */ + /* auto-name */ + BLI_strncpy(palette->info, name, sizeof(palette->info)); + BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info), + sizeof(palette->info)); + + /* make this one the active one */ + if (setactive) { + BKE_gpencil_palette_setactive(gpd, palette); + } + + /* return palette */ + return palette; +} + +/* create a set of default drawing brushes with predefined presets */ +void BKE_gpencil_brush_init_presets(ToolSettings *ts) +{ + bGPDbrush *brush; + /* Basic brush */ + brush = BKE_gpencil_brush_addnew(ts, "Basic", true); + brush->thickness = 3.0f; + brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; + brush->draw_sensitivity = 1.0f; + brush->flag |= GP_BRUSH_USE_PRESSURE; + + brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; + brush->draw_strength = 1.0f; + brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->draw_random_press = 0.0f; + + brush->draw_jitter = 0.0f; + brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->draw_angle = 0.0f; + brush->draw_angle_factor = 0.0f; + + brush->draw_smoothfac = 0.0f; + brush->draw_smoothlvl = 1; + brush->sublevel = 0; + brush->draw_random_sub = 0.0f; + + /* Pencil brush */ + brush = BKE_gpencil_brush_addnew(ts, "Pencil", false); + brush->thickness = 7.0f; + brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; + brush->draw_sensitivity = 1.0f; + brush->flag |= GP_BRUSH_USE_PRESSURE; + + brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; + brush->draw_strength = 0.7f; + brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->draw_random_press = 0.0f; + + brush->draw_jitter = 0.0f; + brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->draw_angle = 0.0f; + brush->draw_angle_factor = 0.0f; + + brush->draw_smoothfac = 1.0f; + brush->draw_smoothlvl = 2; + brush->sublevel = 2; + brush->draw_random_sub = 0.0f; + + /* Ink brush */ + brush = BKE_gpencil_brush_addnew(ts, "Ink", false); + brush->thickness = 7.0f; + brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; + brush->draw_sensitivity = 1.6f; + brush->flag |= GP_BRUSH_USE_PRESSURE; + + brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; + brush->draw_strength = 1.0f; + brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->draw_random_press = 0.0f; + + brush->draw_jitter = 0.0f; + brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->draw_angle = 0.0f; + brush->draw_angle_factor = 0.0f; + + brush->draw_smoothfac = 1.1f; + brush->draw_smoothlvl = 2; + brush->sublevel = 2; + brush->draw_random_sub = 0.0f; + + /* Ink Noise brush */ + brush = BKE_gpencil_brush_addnew(ts, "Ink noise", false); + brush->thickness = 6.0f; + brush->flag |= GP_BRUSH_USE_RANDOM_PRESSURE; + brush->draw_sensitivity = 1.611f; + brush->flag |= GP_BRUSH_USE_PRESSURE; + + brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; + brush->draw_strength = 1.0f; + brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->draw_random_press = 1.0f; + + brush->draw_jitter = 0.0f; + brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->draw_angle = 0.0f; + brush->draw_angle_factor = 0.0f; + + brush->draw_smoothfac = 1.1f; + brush->draw_smoothlvl = 2; + brush->sublevel = 2; + brush->draw_random_sub = 0.0f; + + /* Marker brush */ + brush = BKE_gpencil_brush_addnew(ts, "Marker", false); + brush->thickness = 10.0f; + brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; + brush->draw_sensitivity = 2.0f; + brush->flag &= ~GP_BRUSH_USE_PRESSURE; + + brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; + brush->draw_strength = 1.0f; + brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->draw_random_press = 0.0f; + + brush->draw_jitter = 0.0f; + brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->draw_angle = M_PI_4; /* 45 degrees */ + brush->draw_angle_factor = 1.0f; + + brush->draw_smoothfac = 1.0f; + brush->draw_smoothlvl = 2; + brush->sublevel = 2; + brush->draw_random_sub = 0.0f; + + /* Crayon brush */ + brush = BKE_gpencil_brush_addnew(ts, "Crayon", false); + brush->thickness = 10.0f; + brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; + brush->draw_sensitivity = 3.0f; + brush->flag &= ~GP_BRUSH_USE_PRESSURE; + + brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; + brush->draw_strength = 0.140f; + brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->draw_random_press = 0.0f; + + brush->draw_jitter = 0.0f; + brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->draw_angle = 0.0f; + brush->draw_angle_factor = 0.0f; + + brush->draw_smoothfac = 0.0f; + brush->draw_smoothlvl = 1; + brush->sublevel = 2; + brush->draw_random_sub = 0.5f; + +} + +/* add a new gp-brush and make it the active */ +bGPDbrush *BKE_gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive) +{ + bGPDbrush *brush; + + /* check that list is ok */ + if (ts == NULL) { + return NULL; + } + + /* allocate memory and add to end of list */ + brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush"); + + /* add to datablock */ + BLI_addtail(&ts->gp_brushes, brush); + + /* set basic settings */ + brush->thickness = 3; + brush->draw_smoothlvl = 1; + brush->flag |= GP_BRUSH_USE_PRESSURE; + brush->draw_sensitivity = 1.0f; + brush->draw_strength = 1.0f; + brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->draw_jitter = 0.0f; + brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + /* curves */ + brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + + /* auto-name */ + BLI_strncpy(brush->info, name, sizeof(brush->info)); + BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info)); + + /* make this one the active one */ + if (setactive) { + BKE_gpencil_brush_setactive(ts, brush); + } + + /* return brush */ + return brush; +} + +/* add a new gp-palettecolor and make it the active */ +bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive) +{ + bGPDpalettecolor *palcolor; + + /* check that list is ok */ + if (palette == NULL) { + return NULL; + } + + /* allocate memory and add to end of list */ + palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor"); + + /* add to datablock */ + BLI_addtail(&palette->colors, palcolor); + + /* set basic settings */ + palcolor->flag |= PC_COLOR_HQ_FILL; + copy_v4_v4(palcolor->color, U.gpencil_new_layer_col); + ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f); + + /* auto-name */ + BLI_strncpy(palcolor->info, name, sizeof(palcolor->info)); + BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info), + sizeof(palcolor->info)); + + /* make this one the active one */ + if (setactive) { + BKE_gpencil_palettecolor_setactive(palette, palcolor); + } + + /* return palette color */ + return palcolor; +} + /* add a new gp-datablock */ -bGPdata *gpencil_data_addnew(const char name[]) +bGPdata *BKE_gpencil_data_addnew(const char name[]) { bGPdata *gpd; @@ -300,94 +641,157 @@ bGPdata *gpencil_data_addnew(const char name[]) /* -------- Data Duplication ---------- */ /* make a copy of a given gpencil frame */ -bGPDframe *gpencil_frame_duplicate(bGPDframe *src) +bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) { - bGPDstroke *gps, *gpsd; - bGPDframe *dst; + bGPDstroke *gps_dst; + bGPDframe *gpf_dst; /* error checking */ - if (src == NULL) + if (gpf_src == NULL) { return NULL; + } /* make a copy of the source frame */ - dst = MEM_dupallocN(src); - dst->prev = dst->next = NULL; + gpf_dst = MEM_dupallocN(gpf_src); + gpf_dst->prev = gpf_dst->next = NULL; /* copy strokes */ - BLI_listbase_clear(&dst->strokes); - for (gps = src->strokes.first; gps; gps = gps->next) { + BLI_listbase_clear(&gpf_dst->strokes); + for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { /* make copy of source stroke, then adjust pointer to points too */ - gpsd = MEM_dupallocN(gps); - gpsd->points = MEM_dupallocN(gps->points); - gpsd->triangles = MEM_dupallocN(gps->triangles); - gpsd->flag |= GP_STROKE_RECALC_CACHES; - BLI_addtail(&dst->strokes, gpsd); + gps_dst = MEM_dupallocN(gps_src); + gps_dst->points = MEM_dupallocN(gps_src->points); + gps_dst->triangles = MEM_dupallocN(gps_src->triangles); + gps_dst->flag |= GP_STROKE_RECALC_CACHES; + BLI_addtail(&gpf_dst->strokes, gps_dst); } /* return new frame */ - return dst; + return gpf_dst; +} + +/* make a copy of a given gpencil brush */ +bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src) +{ + bGPDbrush *brush_dst; + + /* error checking */ + if (brush_src == NULL) { + return NULL; + } + + /* make a copy of source brush */ + brush_dst = MEM_dupallocN(brush_src); + brush_dst->prev = brush_dst->next = NULL; + /* make a copy of curves */ + brush_dst->cur_sensitivity = curvemapping_copy(brush_src->cur_sensitivity); + brush_dst->cur_strength = curvemapping_copy(brush_src->cur_strength); + brush_dst->cur_jitter = curvemapping_copy(brush_src->cur_jitter); + + /* return new brush */ + return brush_dst; } +/* make a copy of a given gpencil palette */ +bGPDpalette *BKE_gpencil_palette_duplicate(const bGPDpalette *palette_src) +{ + bGPDpalette *palette_dst; + const bGPDpalettecolor *palcolor_src; + bGPDpalettecolor *palcolord_dst; + + /* error checking */ + if (palette_src == NULL) { + return NULL; + } + + /* make a copy of source palette */ + palette_dst = MEM_dupallocN(palette_src); + palette_dst->prev = palette_dst->next = NULL; + + /* copy colors */ + BLI_listbase_clear(&palette_dst->colors); + for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) { + /* make a copy of source */ + palcolord_dst = MEM_dupallocN(palcolor_src); + BLI_addtail(&palette_dst->colors, palcolord_dst); + } + + /* return new palette */ + return palette_dst; +} /* make a copy of a given gpencil layer */ -bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src) +bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) { - bGPDframe *gpf, *gpfd; - bGPDlayer *dst; + const bGPDframe *gpf_src; + bGPDframe *gpf_dst; + bGPDlayer *gpl_dst; /* error checking */ - if (src == NULL) + if (gpl_src == NULL) { return NULL; + } /* make a copy of source layer */ - dst = MEM_dupallocN(src); - dst->prev = dst->next = NULL; + gpl_dst = MEM_dupallocN(gpl_src); + gpl_dst->prev = gpl_dst->next = NULL; /* copy frames */ - BLI_listbase_clear(&dst->frames); - for (gpf = src->frames.first; gpf; gpf = gpf->next) { + BLI_listbase_clear(&gpl_dst->frames); + for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) { /* make a copy of source frame */ - gpfd = gpencil_frame_duplicate(gpf); - BLI_addtail(&dst->frames, gpfd); + gpf_dst = BKE_gpencil_frame_duplicate(gpf_src); + BLI_addtail(&gpl_dst->frames, gpf_dst); /* if source frame was the current layer's 'active' frame, reassign that too */ - if (gpf == dst->actframe) - dst->actframe = gpfd; + if (gpf_src == gpl_dst->actframe) + gpl_dst->actframe = gpf_dst; } /* return new layer */ - return dst; + return gpl_dst; } /* make a copy of a given gpencil datablock */ -bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy) +bGPdata *BKE_gpencil_data_duplicate(Main *bmain, bGPdata *gpd_src, bool internal_copy) { - bGPDlayer *gpl, *gpld; - bGPdata *dst; - + const bGPDlayer *gpl_src; + bGPDlayer *gpl_dst; + bGPdata *gpd_dst; + /* error checking */ - if (src == NULL) + if (gpd_src == NULL) { return NULL; + } /* make a copy of the base-data */ if (internal_copy) { /* make a straight copy for undo buffers used during stroke drawing */ - dst = MEM_dupallocN(src); + gpd_dst = MEM_dupallocN(gpd_src); } else { /* make a copy when others use this */ - dst = BKE_libblock_copy(bmain, &src->id); + gpd_dst = BKE_libblock_copy(bmain, &gpd_src->id); } /* copy layers */ - BLI_listbase_clear(&dst->layers); - for (gpl = src->layers.first; gpl; gpl = gpl->next) { + BLI_listbase_clear(&gpd_dst->layers); + for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { /* make a copy of source layer and its data */ - gpld = gpencil_layer_duplicate(gpl); - BLI_addtail(&dst->layers, gpld); + gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); + BLI_addtail(&gpd_dst->layers, gpl_dst); + } + if (!internal_copy) { + /* copy palettes */ + bGPDpalette *palette_src, *palette_dst; + BLI_listbase_clear(&gpd_dst->palettes); + for (palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) { + palette_dst = BKE_gpencil_palette_duplicate(palette_src); + BLI_addtail(&gpd_dst->palettes, palette_dst); + } } /* return new */ - return dst; + return gpd_dst; } void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) @@ -398,7 +802,7 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) /* -------- GP-Stroke API --------- */ /* ensure selection status of stroke is in sync with its points */ -void gpencil_stroke_sync_selection(bGPDstroke *gps) +void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps) { bGPDspoint *pt; int i; @@ -423,7 +827,7 @@ void gpencil_stroke_sync_selection(bGPDstroke *gps) /* -------- GP-Frame API ---------- */ /* delete the last stroke of the given frame */ -void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) +void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) { bGPDstroke *gps = (gpf) ? gpf->strokes.last : NULL; int cfra = (gpf) ? gpf->framenum : 0; /* assume that the current frame was not locked */ @@ -439,8 +843,8 @@ void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) /* if frame has no strokes after this, delete it */ if (BLI_listbase_is_empty(&gpf->strokes)) { - gpencil_layer_delframe(gpl, gpf); - gpencil_layer_getframe(gpl, cfra, 0); + BKE_gpencil_layer_delframe(gpl, gpf); + BKE_gpencil_layer_getframe(gpl, cfra, 0); } } @@ -458,7 +862,7 @@ bool gpencil_layer_is_editable(const bGPDlayer *gpl) /* Opacity must be sufficiently high that it is still "visible" * Otherwise, it's not really "visible" to the user, so no point editing... */ - if ((gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH)) { + if (gpl->opacity > GPENCIL_ALPHA_OPACITY_THRESH) { return true; } } @@ -488,7 +892,7 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe) * - this sets the layer's actframe var (if allowed to) * - extension beyond range (if first gp-frame is after all frame in interest and cannot add) */ -bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew) +bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew) { bGPDframe *gpf = NULL; short found = 0; @@ -527,9 +931,9 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode if ((found) && (gpf->framenum == cframe)) gpl->actframe = gpf; else if (addnew == GP_GETFRAME_ADD_COPY) - gpl->actframe = gpencil_frame_addcopy(gpl, cframe); + gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe); else - gpl->actframe = gpencil_frame_addnew(gpl, cframe); + gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe); } else if (found) gpl->actframe = gpf; @@ -549,9 +953,9 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode if ((found) && (gpf->framenum == cframe)) gpl->actframe = gpf; else if (addnew == GP_GETFRAME_ADD_COPY) - gpl->actframe = gpencil_frame_addcopy(gpl, cframe); + gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe); else - gpl->actframe = gpencil_frame_addnew(gpl, cframe); + gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe); } else if (found) gpl->actframe = gpf; @@ -588,7 +992,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode if ((found) && (gpf->framenum == cframe)) gpl->actframe = gpf; else - gpl->actframe = gpencil_frame_addnew(gpl, cframe); + gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe); } else if (found) gpl->actframe = gpf; @@ -601,7 +1005,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode else { /* currently no frames (add if allowed to) */ if (addnew) - gpl->actframe = gpencil_frame_addnew(gpl, cframe); + gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe); else { /* don't do anything... this may be when no frames yet! */ /* gpl->actframe should still be NULL */ @@ -613,7 +1017,7 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode } /* delete the given frame from a layer */ -bool gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) +bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) { bool changed = false; @@ -630,14 +1034,14 @@ bool gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) gpl->actframe = NULL; /* free the frame and its data */ - changed = free_gpencil_strokes(gpf); + changed = BKE_gpencil_free_strokes(gpf); BLI_freelinkN(&gpl->frames, gpf); return changed; } /* get the active gp-layer for editing */ -bGPDlayer *gpencil_layer_getactive(bGPdata *gpd) +bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd) { bGPDlayer *gpl; @@ -656,7 +1060,7 @@ bGPDlayer *gpencil_layer_getactive(bGPdata *gpd) } /* set the active gp-layer */ -void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) +void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) { bGPDlayer *gpl; @@ -673,15 +1077,255 @@ void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) } /* delete the active gp-layer */ -void gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl) +void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl) { /* error checking */ if (ELEM(NULL, gpd, gpl)) return; /* free layer */ - free_gpencil_frames(gpl); + BKE_gpencil_free_frames(gpl); BLI_freelinkN(&gpd->layers, gpl); } /* ************************************************** */ +/* get the active gp-brush for editing */ +bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts) +{ + bGPDbrush *brush; + + /* error checking */ + if (ELEM(NULL, ts, ts->gp_brushes.first)) { + return NULL; + } + + /* loop over brushes until found (assume only one active) */ + for (brush = ts->gp_brushes.first; brush; brush = brush->next) { + if (brush->flag & GP_BRUSH_ACTIVE) { + return brush; + } + } + + /* no active brush found */ + return NULL; +} + +/* set the active gp-brush */ +void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active) +{ + bGPDbrush *brush; + + /* error checking */ + if (ELEM(NULL, ts, ts->gp_brushes.first, active)) { + return; + } + + /* loop over brushes deactivating all */ + for (brush = ts->gp_brushes.first; brush; brush = brush->next) { + brush->flag &= ~GP_BRUSH_ACTIVE; + } + + /* set as active one */ + active->flag |= GP_BRUSH_ACTIVE; +} + +/* delete the active gp-brush */ +void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush) +{ + /* error checking */ + if (ELEM(NULL, ts, brush)) { + return; + } + + /* free curves */ + if (brush->cur_sensitivity) { + curvemapping_free(brush->cur_sensitivity); + } + if (brush->cur_strength) { + curvemapping_free(brush->cur_strength); + } + if (brush->cur_jitter) { + curvemapping_free(brush->cur_jitter); + } + + /* free */ + BLI_freelinkN(&ts->gp_brushes, brush); +} + +/* ************************************************** */ +/* get the active gp-palette for editing */ +bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd) +{ + bGPDpalette *palette; + + /* error checking */ + if (ELEM(NULL, gpd, gpd->palettes.first)) { + return NULL; + } + + /* loop over palettes until found (assume only one active) */ + for (palette = gpd->palettes.first; palette; palette = palette->next) { + if (palette->flag & PL_PALETTE_ACTIVE) + return palette; + } + + /* no active palette found */ + return NULL; +} + +/* set the active gp-palette */ +void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active) +{ + bGPDpalette *palette; + + /* error checking */ + if (ELEM(NULL, gpd, gpd->palettes.first, active)) { + return; + } + + /* loop over palettes deactivating all */ + for (palette = gpd->palettes.first; palette; palette = palette->next) { + palette->flag &= ~PL_PALETTE_ACTIVE; + } + + /* set as active one */ + active->flag |= PL_PALETTE_ACTIVE; + /* force color recalc */ + BKE_gpencil_palette_change_strokes(gpd); +} + +/* delete the active gp-palette */ +void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette) +{ + /* error checking */ + if (ELEM(NULL, gpd, palette)) { + return; + } + + /* free colors */ + free_gpencil_colors(palette); + BLI_freelinkN(&gpd->palettes, palette); + /* force color recalc */ + BKE_gpencil_palette_change_strokes(gpd); +} + +/* Set all strokes to recalc the palette color */ +void BKE_gpencil_palette_change_strokes(bGPdata *gpd) +{ + bGPDlayer *gpl; + bGPDframe *gpf; + bGPDstroke *gps; + + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (gps = gpf->strokes.first; gps; gps = gps->next) { + gps->flag |= GP_STROKE_RECALC_COLOR; + } + } + } +} + + +/* get the active gp-palettecolor for editing */ +bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette) +{ + bGPDpalettecolor *palcolor; + + /* error checking */ + if (ELEM(NULL, palette, palette->colors.first)) { + return NULL; + } + + /* loop over colors until found (assume only one active) */ + for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { + if (palcolor->flag & PC_COLOR_ACTIVE) { + return palcolor; + } + } + + /* no active color found */ + return NULL; +} +/* get the gp-palettecolor looking for name */ +bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name) +{ + /* error checking */ + if (ELEM(NULL, palette, name)) { + return NULL; + } + + return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info)); +} + +/* Change color name in all strokes */ +void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname) +{ + bGPDlayer *gpl; + bGPDframe *gpf; + bGPDstroke *gps; + + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (gps = gpf->strokes.first; gps; gps = gps->next) { + if (STREQ(gps->colorname, oldname)) { + strcpy(gps->colorname, newname); + } + } + } + } + +} + +/* Delete all strokes of the color */ +void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name) +{ + bGPDlayer *gpl; + bGPDframe *gpf; + bGPDstroke *gps, *gpsn; + + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + + if (STREQ(gps->colorname, name)) { + if (gps->points) MEM_freeN(gps->points); + if (gps->triangles) MEM_freeN(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + } + } + } + } + +} + +/* set the active gp-palettecolor */ +void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active) +{ + bGPDpalettecolor *palcolor; + + /* error checking */ + if (ELEM(NULL, palette, palette->colors.first, active)) { + return; + } + + /* loop over colors deactivating all */ + for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { + palcolor->flag &= ~PC_COLOR_ACTIVE; + } + + /* set as active one */ + active->flag |= PC_COLOR_ACTIVE; +} + +/* delete the active gp-palettecolor */ +void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor) +{ + /* error checking */ + if (ELEM(NULL, palette, palcolor)) { + return; + } + + /* free */ + BLI_freelinkN(&palette->colors, palcolor); +} diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index c7a346d49ec..ddc4fb37848 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -60,6 +60,7 @@ static IDType idtypes[] = { { ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE }, { ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE }, { ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE }, + { ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE }, { ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE }, { ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */ { ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE }, @@ -183,6 +184,7 @@ int BKE_idcode_to_idfilter(const short idcode) CASE_IDFILTER(AR); CASE_IDFILTER(BR); CASE_IDFILTER(CA); + CASE_IDFILTER(CF); CASE_IDFILTER(CU); CASE_IDFILTER(GD); CASE_IDFILTER(GR); @@ -225,6 +227,7 @@ short BKE_idcode_from_idfilter(const int idfilter) CASE_IDFILTER(AR); CASE_IDFILTER(BR); CASE_IDFILTER(CA); + CASE_IDFILTER(CF); CASE_IDFILTER(CU); CASE_IDFILTER(GD); CASE_IDFILTER(GR); diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 86d010f5f7c..b2641b110f8 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -940,17 +940,18 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * prop->subtype = IDP_STRING_SUB_BYTE; } else { - if (st == NULL) { + if (st == NULL || val->string.len <= 1) { prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); *IDP_String(prop) = '\0'; prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ } else { - int stlen = (int)strlen(st) + 1; - prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 3"); - prop->len = prop->totallen = stlen; - memcpy(prop->data.pointer, st, (size_t)stlen); + BLI_assert((int)val->string.len <= (int)strlen(st) + 1); + prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 3"); + memcpy(prop->data.pointer, st, (size_t)val->string.len - 1); + IDP_String(prop)[val->string.len - 1] = '\0'; + prop->len = prop->totallen = val->string.len; } prop->subtype = IDP_STRING_SUB_UTF8; } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ea28dabb945..626d389ac2d 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -436,6 +436,7 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src) Image *BKE_image_copy(Main *bmain, Image *ima) { Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type); + ima->id.newid = &nima->id; BLI_strncpy(nima->name, ima->name, sizeof(ima->name)); diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 558c3bb0326..933622eed83 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -45,6 +45,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_brush_types.h" +#include "DNA_cachefile_types.h" #include "DNA_camera_types.h" #include "DNA_group_types.h" #include "DNA_gpencil_types.h" @@ -56,6 +57,7 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" +#include "DNA_modifier_types.h" #include "DNA_movieclip_types.h" #include "DNA_mask_types.h" #include "DNA_node_types.h" @@ -81,6 +83,7 @@ #include "BKE_bpath.h" #include "BKE_brush.h" #include "BKE_camera.h" +#include "BKE_cachefile.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" @@ -103,8 +106,10 @@ #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_mask.h" +#include "BKE_movieclip.h" #include "BKE_node.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_packedFile.h" #include "BKE_sound.h" #include "BKE_speaker.h" @@ -318,7 +323,6 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c } } } - } /** @@ -330,16 +334,16 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c */ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) { - if (id->tag & LIB_TAG_INDIRECT) + /* We don't care whether ID is directly or indirectly linked in case we are making a whole lib local... */ + if (!lib_local && (id->tag & LIB_TAG_INDIRECT)) { return false; + } - switch (GS(id->name)) { + switch ((ID_Type)GS(id->name)) { case ID_SCE: /* Partially implemented (has no copy...). */ if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local); return true; - case ID_LI: - return false; /* can't be linked */ case ID_OB: if (!test) BKE_object_make_local(bmain, (Object *)id, lib_local); return true; @@ -373,15 +377,9 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) case ID_SPK: if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local); return true; - case ID_IP: - return false; /* deprecated */ - case ID_KE: - return false; /* can't be linked */ case ID_WO: if (!test) BKE_world_make_local(bmain, (World *)id, lib_local); return true; - case ID_SCR: - return false; /* can't be linked */ case ID_VF: /* Partially implemented (has no copy...). */ if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local); @@ -408,17 +406,34 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) case ID_BR: if (!test) BKE_brush_make_local(bmain, (Brush *)id, lib_local); return true; - case ID_WM: - return false; /* can't be linked */ case ID_GD: if (!test) BKE_gpencil_make_local(bmain, (bGPdata *)id, lib_local); return true; + case ID_MC: + if (!test) BKE_movieclip_make_local(bmain, (MovieClip *)id, lib_local); + return true; case ID_MSK: if (!test) BKE_mask_make_local(bmain, (Mask *)id, lib_local); return true; case ID_LS: if (!test) BKE_linestyle_make_local(bmain, (FreestyleLineStyle *)id, lib_local); return true; + case ID_PAL: + if (!test) BKE_palette_make_local(bmain, (Palette *)id, lib_local); + return true; + case ID_PC: + if (!test) BKE_paint_curve_make_local(bmain, (PaintCurve *)id, lib_local); + return true; + case ID_CF: + if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local); + return true; + case ID_SCR: + case ID_LI: + case ID_KE: + case ID_WM: + return false; /* can't be linked */ + case ID_IP: + return false; /* deprecated */ } return false; @@ -437,11 +452,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test) /* conventions: * - make shallow copy, only this ID block * - id.us of the new ID is set to 1 */ - switch (GS(id->name)) { - case ID_SCE: - return false; /* can't be copied from here */ - case ID_LI: - return false; /* can't be copied from here */ + switch ((ID_Type)GS(id->name)) { case ID_OB: if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id); return true; @@ -475,23 +486,15 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test) case ID_CA: if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id); return true; - case ID_IP: - return false; /* deprecated */ case ID_KE: if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id); return true; case ID_WO: if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id); return true; - case ID_SCR: - return false; /* can't be copied from here */ - case ID_VF: - return false; /* not implemented */ case ID_TXT: if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id); return true; - case ID_SO: - return false; /* not implemented */ case ID_GR: if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id); return true; @@ -507,10 +510,11 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test) case ID_BR: if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id); return true; - case ID_WM: - return false; /* can't be copied from here */ case ID_GD: - if (!test) *newid = (ID *)gpencil_data_duplicate(bmain, (bGPdata *)id, false); + if (!test) *newid = (ID *)BKE_gpencil_data_duplicate(bmain, (bGPdata *)id, false); + return true; + case ID_MC: + if (!test) *newid = (ID *)BKE_movieclip_copy(bmain, (MovieClip *)id); return true; case ID_MSK: if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id); @@ -518,6 +522,25 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test) case ID_LS: if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id); return true; + case ID_PAL: + if (!test) *newid = (ID *)BKE_palette_copy(bmain, (Palette *)id); + return true; + case ID_PC: + if (!test) *newid = (ID *)BKE_paint_curve_copy(bmain, (PaintCurve *)id); + return true; + case ID_CF: + if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id); + return true; + case ID_SCE: + case ID_LI: + case ID_SCR: + case ID_WM: + return false; /* can't be copied from here */ + case ID_VF: + case ID_SO: + return false; /* not implemented */ + case ID_IP: + return false; /* deprecated */ } return false; @@ -553,7 +576,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) ListBase *which_libbase(Main *mainlib, short type) { - switch (type) { + switch ((ID_Type)type) { case ID_SCE: return &(mainlib->scene); case ID_LI: @@ -618,6 +641,8 @@ ListBase *which_libbase(Main *mainlib, short type) return &(mainlib->palettes); case ID_PC: return &(mainlib->paintcurves); + case ID_CF: + return &(mainlib->cachefiles); } return NULL; } @@ -741,6 +766,7 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[a++] = &(main->armature); + lb[a++] = &(main->cachefiles); lb[a++] = &(main->mesh); lb[a++] = &(main->curve); lb[a++] = &(main->mball); @@ -791,7 +817,7 @@ void *BKE_libblock_alloc_notest(short type) { ID *id = NULL; - switch (type) { + switch ((ID_Type)type) { case ID_SCE: id = MEM_callocN(sizeof(Scene), "scene"); break; @@ -888,6 +914,9 @@ void *BKE_libblock_alloc_notest(short type) case ID_PC: id = MEM_callocN(sizeof(PaintCurve), "Paint Curve"); break; + case ID_CF: + id = MEM_callocN(sizeof(CacheFile), "Cache File"); + break; } return id; } @@ -925,7 +954,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name) void BKE_libblock_init_empty(ID *id) { /* Note that only ID types that are not valid when filled of zero should have a callback here. */ - switch (GS(id->name)) { + switch ((ID_Type)GS(id->name)) { case ID_SCE: BKE_scene_init((Scene *)id); break; @@ -969,15 +998,6 @@ void BKE_libblock_init_empty(ID *id) case ID_CA: BKE_camera_init((Camera *)id); break; - case ID_IP: - /* Should not be needed - animation from lib pre-2.5 is broken anyway. */ - BLI_assert(0); - break; - case ID_KE: - /* Shapekeys are a complex topic too - they depend on their 'user' data type... - * They are not linkable, though, so it should never reach here anyway. */ - BLI_assert(0); - break; case ID_WO: BKE_world_init((World *)id); break; @@ -1011,10 +1031,6 @@ void BKE_libblock_init_empty(ID *id) case ID_PC: /* Nothing to do. */ break; - case ID_WM: - /* We should never reach this. */ - BLI_assert(0); - break; case ID_GD: /* Nothing to do. */ break; @@ -1024,6 +1040,24 @@ void BKE_libblock_init_empty(ID *id) case ID_LS: BKE_linestyle_init((FreestyleLineStyle *)id); break; + case ID_CF: + BKE_cachefile_init((CacheFile *)id); + break; + case ID_KE: + /* Shapekeys are a complex topic too - they depend on their 'user' data type... + * They are not linkable, though, so it should never reach here anyway. */ + BLI_assert(0); + break; + case ID_WM: + /* We should never reach this. */ + BLI_assert(0); + break; + case ID_IP: + /* Should not be needed - animation from lib pre-2.5 is broken anyway. */ + BLI_assert(0); + break; + default: + BLI_assert(0); /* Should never reach this point... */ } } @@ -1607,7 +1641,13 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged int a; for (a = set_listbasepointers(bmain, lbarray); a--; ) { - for (id = lbarray[a]->first; id; id = id_next) { + id = lbarray[a]->first; + + /* Do not explicitly make local non-linkable IDs (shapekeys, in fact), they are assumed to be handled + * by real datablocks responsible of them. */ + const bool do_skip = (id && BKE_idcode_is_linkable(GS(id->name))); + + for (; id; id = id_next) { id->newid = NULL; id_next = id->next; /* id is possibly being inserted again */ @@ -1616,7 +1656,7 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged * appending data, so any libdata already linked wont become local * (very nasty to discover all your links are lost after appending) * */ - if (id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && + if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) { if (lib == NULL || id->lib == lib) { diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 17c90286a5b..eb71a42fb77 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -295,7 +295,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_animationData(&data, adt); } - switch (GS(id->name)) { + switch ((ID_Type)GS(id->name)) { case ID_LI: { Library *lib = (Library *) id; @@ -480,6 +480,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data); BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data); + if (object->soft) { + CALLBACK_INVOKE(object->soft->collision_group, IDWALK_NOP); + + if (object->soft->effector_weights) { + CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP); + } + } + BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data); BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data); BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data); @@ -616,6 +624,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_KE: { + /* XXX Only ID pointer from shapekeys is the 'from' one, which is not actually ID usage. + * Maybe we should even nuke it from here, not 100% sure yet... + * (see also foreach_libblock_id_users_callback). + */ Key *key = (Key *) id; CALLBACK_INVOKE_ID(key->from, IDWALK_NOP); break; @@ -764,6 +776,25 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } break; } + + /* Nothing needed for those... */ + case ID_IM: + case ID_VF: + case ID_TXT: + case ID_SO: + case ID_AR: + case ID_AC: + case ID_GD: + case ID_WM: + case ID_PAL: + case ID_PC: + case ID_CF: + break; + + /* Deprecated. */ + case ID_IP: + break; + } } while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL)); @@ -880,10 +911,18 @@ typedef struct IDUsersIter { int count_direct, count_indirect; /* Set by callback. */ } IDUsersIter; -static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag) +static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID **id_p, int cb_flag) { IDUsersIter *iter = user_data; + /* XXX This is actually some kind of hack... + * Issue is, only ID pointer from shapekeys is the 'from' one, which is not actually ID usage. + * Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet... + */ + if (GS(self_id->name) == ID_KE) { + return IDWALK_RET_NOP; + } + if (*id_p && (*id_p == iter->id)) { #if 0 printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n", diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 92652fcc1eb..4afce3b5f85 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -38,6 +38,7 @@ #include "DNA_armature_types.h" #include "DNA_brush_types.h" #include "DNA_camera_types.h" +#include "DNA_cachefile_types.h" #include "DNA_group_types.h" #include "DNA_gpencil_types.h" #include "DNA_ipo_types.h" @@ -69,6 +70,7 @@ #include "BKE_armature.h" #include "BKE_brush.h" #include "BKE_camera.h" +#include "BKE_cachefile.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_fcurve.h" @@ -791,7 +793,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) free_windowmanager_cb(NULL, (wmWindowManager *)id); break; case ID_GD: - BKE_gpencil_free((bGPdata *)id); + BKE_gpencil_free((bGPdata *)id, true); break; case ID_MC: BKE_movieclip_free((MovieClip *)id); @@ -808,6 +810,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) case ID_PC: BKE_paint_curve_free((PaintCurve *)id); break; + case ID_CF: + BKE_cachefile_free((CacheFile *)id); + break; } /* avoid notifying on removed data */ diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 0be32c9b84c..470108545b8 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -742,17 +742,18 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type) if (mao) id_us_min(&mao->id); ob->mat[act - 1] = ma; + test_object_materials(ob, ob->data); } else { /* in data */ mao = (*matarar)[act - 1]; if (mao) id_us_min(&mao->id); (*matarar)[act - 1] = ma; + test_all_objects_materials(G.main, ob->data); /* Data may be used by several objects... */ } if (ma) id_us_plus(&ma->id); - test_object_materials(ob, ob->data); } diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 1c86fbcfe8e..fa113ef5eef 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -434,7 +434,7 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) } /* This threshold is a bit touchy (usual float precision issue), this value seems OK. */ -#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-6f) +#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f) /* Should only be called once. * Beware, this modifies ref_vec and other_vec in place! diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index f99457a4c26..0d362086134 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1491,6 +1491,32 @@ void BKE_movieclip_free(MovieClip *clip) BKE_tracking_free(&clip->tracking); } +MovieClip *BKE_movieclip_copy(Main *bmain, MovieClip *clip) +{ + MovieClip *clip_new; + + clip_new = BKE_libblock_copy(bmain, &clip->id); + + clip_new->anim = NULL; + clip_new->cache = NULL; + + BKE_tracking_copy(&clip_new->tracking, &clip->tracking); + clip_new->tracking_context = NULL; + + id_us_plus((ID *)clip_new->gpd); + + BKE_color_managed_colorspace_settings_copy(&clip_new->colorspace_settings, &clip->colorspace_settings); + + BKE_id_copy_ensure_local(bmain, &clip->id, &clip_new->id); + + return clip_new; +} + +void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &clip->id, true, lib_local); +} + float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr) { return framenr - (float) clip->start_frame + 1.0f; diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 4716f8dc40a..75f20c7e1d3 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -80,7 +80,6 @@ typedef struct DupliContext { int persistent_id[MAX_DUPLI_RECUR]; int level; - int index; const struct DupliGenerator *gen; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 8c1502643c5..53675f33a69 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -314,6 +314,26 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) return pc; } +PaintCurve *BKE_paint_curve_copy(Main *bmain, PaintCurve *pc) +{ + PaintCurve *pc_new; + + pc_new = BKE_libblock_copy(bmain, &pc->id); + + if (pc->tot_points != 0) { + pc_new->points = MEM_dupallocN(pc->points); + } + + BKE_id_copy_ensure_local(bmain, &pc->id, &pc_new->id); + + return pc_new; +} + +void BKE_paint_curve_make_local(Main *bmain, PaintCurve *pc, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &pc->id, true, lib_local); +} + Palette *BKE_paint_palette(Paint *p) { return p ? p->palette : NULL; @@ -376,6 +396,24 @@ Palette *BKE_palette_add(Main *bmain, const char *name) return palette; } +Palette *BKE_palette_copy(Main *bmain, Palette *palette) +{ + Palette *palette_new; + + palette_new = BKE_libblock_copy(bmain, &palette->id); + + BLI_duplicatelist(&palette_new->colors, &palette->colors); + + BKE_id_copy_ensure_local(bmain, &palette->id, &palette_new->id); + + return palette_new; +} + +void BKE_palette_make_local(Main *bmain, Palette *palette, bool lib_local) +{ + BKE_id_make_local_generic(bmain, &palette->id, true, lib_local); +} + /** Free (or release) any data used by this palette (does not free the palette itself). */ void BKE_palette_free(Palette *palette) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a75522d5573..c3e34347e55 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -49,6 +49,7 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_gpencil_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -64,6 +65,7 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_cachefile.h" #include "BKE_colortools.h" #include "BKE_depsgraph.h" #include "BKE_editmesh.h" @@ -285,6 +287,13 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint); ts->imapaint.paintcursor = NULL; id_us_plus((ID *)ts->imapaint.stencil); + /* duplicate Grease Pencil Drawing Brushes */ + BLI_listbase_clear(&ts->gp_brushes); + for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { + bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); + BLI_addtail(&ts->gp_brushes, newbrush); + } + } /* make a private copy of the avicodecdata */ @@ -333,7 +342,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) /* grease pencil */ if (scen->gpd) { if (type == SCE_COPY_FULL) { - scen->gpd = gpencil_data_duplicate(bmain, scen->gpd, false); + scen->gpd = BKE_gpencil_data_duplicate(bmain, scen->gpd, false); } else if (type == SCE_COPY_EMPTY) { scen->gpd = NULL; @@ -431,6 +440,10 @@ void BKE_scene_free(Scene *sce) BKE_paint_free(&sce->toolsettings->uvsculpt->paint); MEM_freeN(sce->toolsettings->uvsculpt); } + /* free Grease Pencil Drawing Brushes */ + BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes); + BLI_freelistN(&sce->toolsettings->gp_brushes); + BKE_paint_free(&sce->toolsettings->imapaint.paint); MEM_freeN(sce->toolsettings); @@ -744,6 +757,11 @@ void BKE_scene_init(Scene *sce) gp_brush->strength = 0.5f; gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH]; + gp_brush->size = 25; + gp_brush->strength = 0.5f; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB]; gp_brush->size = 50; gp_brush->strength = 0.3f; @@ -1889,6 +1907,9 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, BKE_mask_evaluate_all_masks(bmain, ctime, true); + /* Update animated cache files for modifiers. */ + BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base)); + #ifdef POSE_ANIMATION_WORKAROUND scene_armature_depsgraph_workaround(bmain); #endif diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 8e7b66ef183..98bea27ecb9 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -691,6 +691,7 @@ typedef struct ObstaclesFromDMData { bool has_velocity; float *vert_vel; float *velocityX, *velocityY, *velocityZ; + int *num_obstacles; } ObstaclesFromDMData; static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z) @@ -739,8 +740,10 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z) /* tag obstacle cells */ data->obstacle_map[index] = 1; - if (data->has_velocity) + if (data->has_velocity) { data->obstacle_map[index] |= 8; + data->num_obstacles[index]++; + } } } } @@ -748,7 +751,7 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z) static void obstacles_from_derivedmesh( Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs, - unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, float dt) + unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt) { if (!scs->dm) return; { @@ -819,7 +822,8 @@ static void obstacles_from_derivedmesh( .sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri, .tree = &treeData, .obstacle_map = obstacle_map, .has_velocity = has_velocity, .vert_vel = vert_vel, - .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ + .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ, + .num_obstacles = num_obstacles }; BLI_task_parallel_range( sds->res_min[2], sds->res_max[2], &data, obstacles_from_derivedmesh_task_cb, true); @@ -855,6 +859,8 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, float *b = smoke_get_color_b(sds->fluid); unsigned int z; + int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], "smoke_num_obstacles"); + smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz); // TODO: delete old obstacle flags @@ -884,7 +890,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) { SmokeCollSettings *scs = smd2->coll; - obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, dt); + obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt); } } @@ -910,7 +916,15 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, b[z] = 0; } } + /* average velocities from multiple obstacles in one cell */ + if (num_obstacles[z]) { + velx[z] /= num_obstacles[z]; + vely[z] /= num_obstacles[z]; + velz[z] /= num_obstacles[z]; + } } + + MEM_freeN(num_obstacles); } /********************************************************** diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index fc3daa132c6..f4986f7daba 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -64,6 +64,7 @@ variables on the UI for now #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_force.h" +#include "DNA_group_types.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -496,59 +497,98 @@ static void ccd_mesh_free(ccd_Mesh *ccdm) } } -static void ccd_build_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash) +static void ccd_build_deflector_hash_single(GHash *hash, Object *ob) +{ + /* only with deflecting set */ + if (ob->pd && ob->pd->deflect) { + void **val_p; + if (!BLI_ghash_ensure_p(hash, ob, &val_p)) { + ccd_Mesh *ccdmesh = ccd_mesh_make(ob); + *val_p = ccdmesh; + } + } +} + +/** + * \note group overrides scene when not NULL. + */ +static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash) { - Base *base= scene->base.first; Object *ob; if (!hash) return; - while (base) { - /*Only proceed for mesh object in same layer */ - if (base->object->type==OB_MESH && (base->lay & vertexowner->lay)) { - ob= base->object; - if ((vertexowner) && (ob == vertexowner)) { - /* if vertexowner is given we don't want to check collision with owner object */ - base = base->next; + + if (group) { + /* Explicit collision group */ + for (GroupObject *go = group->gobject.first; go; go = go->next) { + ob = go->ob; + + if (ob == vertexowner || ob->type != OB_MESH) continue; - } - /*+++ only with deflecting set */ - if (ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == NULL) { - ccd_Mesh *ccdmesh = ccd_mesh_make(ob); - BLI_ghash_insert(hash, ob, ccdmesh); - }/*--- only with deflecting set */ + ccd_build_deflector_hash_single(hash, ob); + } + } + else { + for (Base *base = scene->base.first; base; base = base->next) { + /*Only proceed for mesh object in same layer */ + if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { + ob= base->object; + if ((vertexowner) && (ob == vertexowner)) { + /* if vertexowner is given we don't want to check collision with owner object */ + continue; + } - }/* mesh && layer*/ - base = base->next; - } /* while (base) */ + ccd_build_deflector_hash_single(hash, ob); + } + } + } } -static void ccd_update_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash) +static void ccd_update_deflector_hash_single(GHash *hash, Object *ob) +{ + if (ob->pd && ob->pd->deflect) { + ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash, ob); + if (ccdmesh) { + ccd_mesh_update(ob, ccdmesh); + } + } +} + +/** + * \note group overrides scene when not NULL. + */ +static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash) { - Base *base= scene->base.first; Object *ob; if ((!hash) || (!vertexowner)) return; - while (base) { - /*Only proceed for mesh object in same layer */ - if (base->object->type==OB_MESH && (base->lay & vertexowner->lay)) { - ob= base->object; - if (ob == vertexowner) { - /* if vertexowner is given we don't want to check collision with owner object */ - base = base->next; + + if (group) { + /* Explicit collision group */ + for (GroupObject *go = group->gobject.first; go; go = go->next) { + ob = go->ob; + + if (ob == vertexowner || ob->type != OB_MESH) continue; - } - /*+++ only with deflecting set */ - if (ob->pd && ob->pd->deflect) { - ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash, ob); - if (ccdmesh) - ccd_mesh_update(ob, ccdmesh); - }/*--- only with deflecting set */ + ccd_update_deflector_hash_single(hash, ob); + } + } + else { + for (Base *base = scene->base.first; base; base = base->next) { + /*Only proceed for mesh object in same layer */ + if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { + ob= base->object; + if (ob == vertexowner) { + /* if vertexowner is given we don't want to check collision with owner object */ + continue; + } - }/* mesh && layer*/ - base = base->next; - } /* while (base) */ + ccd_update_deflector_hash_single(hash, ob); + } + } + } } @@ -934,22 +974,32 @@ static void free_softbody_intern(SoftBody *sb) /* +++ dependency information functions*/ -static int are_there_deflectors(Scene *scene, unsigned int layer) +/** + * \note group overrides scene when not NULL. + */ +static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer) { - Base *base; - - for (base = scene->base.first; base; base= base->next) { - if ( (base->lay & layer) && base->object->pd) { - if (base->object->pd->deflect) + if (group) { + for (GroupObject *go = group->gobject.first; go; go = go->next) { + if (go->ob->pd && go->ob->pd->deflect) return 1; } } + else { + for (Base *base = scene->base.first; base; base= base->next) { + if ( (base->lay & layer) && base->object->pd) { + if (base->object->pd->deflect) + return 1; + } + } + } + return 0; } -static int query_external_colliders(Scene *scene, Object *me) +static int query_external_colliders(Scene *scene, Group *group, Object *me) { - return(are_there_deflectors(scene, me->lay)); + return(are_there_deflectors(scene, group, me->lay)); } /* --- dependency information functions*/ @@ -2197,7 +2247,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl /* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */ /* check conditions for various options */ - do_deflector= query_external_colliders(scene, ob); + do_deflector= query_external_colliders(scene, sb->collision_group, ob); /* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */ do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); @@ -2261,7 +2311,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa } /* check conditions for various options */ - do_deflector= query_external_colliders(scene, ob); + do_deflector= query_external_colliders(scene, sb->collision_group, ob); do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); @@ -3468,11 +3518,11 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) */ if (dtime < 0 || dtime > 10.5f) return; - ccd_update_deflector_hash(scene, ob, sb->scratch->colliderhash); + ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash); if (sb->scratch->needstobuildcollider) { - if (query_external_colliders(scene, ob)) { - ccd_build_deflector_hash(scene, ob, sb->scratch->colliderhash); + if (query_external_colliders(scene, sb->collision_group, ob)) { + ccd_build_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash); } sb->scratch->needstobuildcollider=0; } @@ -3592,9 +3642,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i { SoftBody *sb= ob->soft; float dtime, timescale = 1.0f; - int framedelta, framenr = (int)cfra, startframe = scene->r.sfra, endframe = scene->r.efra; - - framedelta = 1; + int framedelta = 1, framenr = (int)cfra, startframe = scene->r.sfra, endframe = scene->r.efra; /* check for changes in mesh, should only happen in case the mesh * structure changes during an animation */ diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 3b76e456ff7..a56fc0f9abe 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -44,6 +44,7 @@ #include "DNA_scene_types.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_math_base.h" #include "BLI_listbase.h" @@ -55,6 +56,7 @@ #include "BKE_fcurve.h" #include "BKE_tracking.h" +#include "BKE_library.h" #include "BKE_movieclip.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -186,6 +188,133 @@ void BKE_tracking_free(MovieTracking *tracking) tracking_dopesheet_free(&tracking->dopesheet); } +/* Copy the whole list of tracks. */ +static void tracking_tracks_copy(ListBase *tracks_dst, ListBase *tracks_src, GHash *tracks_mapping) +{ + MovieTrackingTrack *track_dst, *track_src; + + BLI_listbase_clear(tracks_dst); + BLI_ghash_clear(tracks_mapping, NULL, NULL); + + for (track_src = tracks_src->first; track_src != NULL; track_src = track_src->next) { + track_dst = MEM_dupallocN(track_src); + if (track_src->markers) { + track_dst->markers = MEM_dupallocN(track_src->markers); + } + id_us_plus(&track_dst->gpd->id); + BLI_addtail(tracks_dst, track_dst); + BLI_ghash_insert(tracks_mapping, track_src, track_dst); + } +} + +/* copy the whole list of plane tracks (need whole MovieTracking structures due to embedded pointers to tracks). + * WARNING: implies tracking_[dst/src] and their tracks have already been copied. */ +static void tracking_plane_tracks_copy(ListBase *plane_tracks_dst, ListBase *plane_tracks_src, GHash *tracks_mapping) +{ + MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src; + + BLI_listbase_clear(plane_tracks_dst); + + for (plane_track_src = plane_tracks_src->first; plane_track_src != NULL; plane_track_src = plane_track_src->next) { + plane_track_dst = MEM_dupallocN(plane_tracks_src); + if (plane_track_src->markers) { + plane_track_dst->markers = MEM_dupallocN(plane_track_src->markers); + } + plane_track_dst->point_tracks = MEM_mallocN(sizeof(*plane_track_dst->point_tracks) * plane_track_dst->point_tracksnr, __func__); + for (int i = 0; i < plane_track_dst->point_tracksnr; i++) { + plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping, plane_track_src->point_tracks[i]); + } + id_us_plus(&plane_track_dst->image->id); + BLI_addtail(plane_tracks_dst, plane_track_dst); + } +} + +/* Copy reconstruction structure. */ +static void tracking_reconstruction_copy( + MovieTrackingReconstruction *reconstruction_dst, MovieTrackingReconstruction *reconstruction_src) +{ + *reconstruction_dst = *reconstruction_src; + if (reconstruction_src->cameras) { + reconstruction_dst->cameras = MEM_dupallocN(reconstruction_src->cameras); + } +} + +/* Copy stabilization structure. */ +static void tracking_stabilization_copy( + MovieTrackingStabilization *stabilization_dst, MovieTrackingStabilization *stabilization_src, + GHash *tracks_mapping) +{ + *stabilization_dst = *stabilization_src; + if (stabilization_src->rot_track) { + stabilization_dst->rot_track = BLI_ghash_lookup(tracks_mapping, stabilization_src->rot_track); + } +} + +/* Copy tracking object. */ +static void tracking_object_copy( + MovieTrackingObject *object_dst, MovieTrackingObject *object_src, GHash *tracks_mapping) +{ + *object_dst = *object_src; + tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping); + tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping); + tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction); +} + +/* Copy list of tracking objects. */ +static void tracking_objects_copy(ListBase *objects_dst, ListBase *objects_src, GHash *tracks_mapping) +{ + MovieTrackingObject *object_dst, *object_src; + + BLI_listbase_clear(objects_dst); + + for (object_src = objects_src->first; object_src != NULL; object_src = object_src->next) { + object_dst = MEM_mallocN(sizeof(*object_dst), __func__); + tracking_object_copy(object_dst, object_src, tracks_mapping); + BLI_addtail(objects_dst, object_dst); + } +} + +/* Copy tracking structure content. */ +void BKE_tracking_copy(MovieTracking *tracking_dst, MovieTracking *tracking_src) +{ + GHash *tracks_mapping = BLI_ghash_ptr_new(__func__); + + *tracking_dst = *tracking_src; + + tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping); + tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping); + tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction); + tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, tracks_mapping); + if (tracking_src->act_track) { + tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track); + } + if (tracking_src->act_plane_track) { + MovieTrackingPlaneTrack *plane_track_src, *plane_track_dst; + for (plane_track_src = tracking_src->plane_tracks.first, plane_track_dst = tracking_dst->plane_tracks.first; + !ELEM(NULL, plane_track_src, plane_track_dst); + plane_track_src = plane_track_src->next, plane_track_dst = plane_track_dst->next) + { + if (plane_track_src == tracking_src->act_plane_track) { + tracking_dst->act_plane_track = plane_track_dst; + break; + } + } + } + + /* Warning! Will override tracks_mapping. */ + tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping); + + /* Those remaining are runtime data, they will be reconstructed as needed, do not bother copying them. */ + tracking_dst->dopesheet.ok = false; + BLI_listbase_clear(&tracking_dst->dopesheet.channels); + BLI_listbase_clear(&tracking_dst->dopesheet.coverage_segments); + + tracking_dst->camera.intrinsics = NULL; + tracking_dst->stats = NULL; + + BLI_ghash_free(tracks_mapping, NULL, NULL); +} + /* Initialize motion tracking settings to default values, * used when new movie clip datablock is creating. */ |