diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2016-11-16 18:36:43 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2016-11-16 18:36:43 +0300 |
commit | d30baf60c662915772e7952c1b715c461cb979ff (patch) | |
tree | 86555e1cc531f988bc6820c451676d59148dc8a7 /source | |
parent | d3947aef590e5f3a7baad48d3957d640a2be946a (diff) | |
parent | 2a2eb0c463bd96d42f7306eb17f88cad87f73aea (diff) |
Merge branch 'master' into openvdb
Diffstat (limited to 'source')
134 files changed, 2414 insertions, 1482 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index c2323100205..78d6f6c7cb9 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -97,6 +97,7 @@ void BKE_armature_where_is(struct bArmature *arm); void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion); void BKE_pose_clear_pointers(struct bPose *pose); void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm); +void BKE_pose_rebuild_ex(struct Object *ob, struct bArmature *arm, const bool sort_bones); void BKE_pose_where_is(struct Scene *scene, struct Object *ob); void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h index 9547eeb9838..84a6d07be7d 100644 --- a/source/blender/blenkernel/BKE_blender_undo.h +++ b/source/blender/blenkernel/BKE_blender_undo.h @@ -42,6 +42,7 @@ extern bool BKE_undo_is_valid(const char *name); extern void BKE_undo_reset(void); extern void BKE_undo_number(struct bContext *C, int nr); extern const char *BKE_undo_get_name(int nr, bool *r_active); +extern const char *BKE_undo_get_name_last(void); extern bool BKE_undo_save_file(const char *filename); extern struct Main *BKE_undo_get_main(struct Scene **r_scene); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 55142510f9e..baf8510dd0d 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 278 -#define BLENDER_SUBVERSION 1 +#define BLENDER_SUBVERSION 3 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 0d82de09165..855eb10976c 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -39,6 +39,7 @@ extern "C" { #include "BLI_compiler_attrs.h" struct BlendThumbnail; +struct GHash; struct ListBase; struct ID; struct ImBuf; @@ -64,7 +65,7 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_ /* library_remap.c (keep here since they're general functions) */ void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); -void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user) ATTR_NONNULL(); +void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) ATTR_NONNULL(); void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL(); void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); @@ -125,8 +126,11 @@ void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id); void BKE_library_free(struct Library *lib); void BKE_library_make_local( - struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake); + struct Main *bmain, const struct Library *lib, struct GHash *old_to_new_ids, + const bool untagged_only, const bool set_fake); +void BKE_id_tag_set_atomic(struct ID *id, int tag); +void BKE_id_tag_clear_atomic(struct ID *id, int tag); /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index c6b63754b57..a7470107c24 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -88,6 +88,7 @@ bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv); bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv); void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked); -void BKE_library_tag_unused_linked_data(struct Main *bmain, const bool do_init_tag); +void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag); +void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain); #endif /* __BKE_LIBRARY_QUERY_H__ */ diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h index a0a885c2a04..19a2220006a 100644 --- a/source/blender/blenkernel/BKE_object_deform.h +++ b/source/blender/blenkernel/BKE_object_deform.h @@ -51,9 +51,11 @@ bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, const bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection); void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup); +void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked); void BKE_object_defgroup_remove_all(struct Object *ob); + /* Select helpers */ enum eVGroupSelect; bool *BKE_object_defgroup_subset_from_select_type( diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 470098f8c7c..dcbb667adca 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -433,8 +433,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name) chan->scaleIn = chan->scaleOut = 1.0f; - chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f; - chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f; + chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI; + chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI; chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f; chan->ikrotweight = chan->iklinweight = 0.0f; unit_m4(chan->constinv); diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index e3764adb969..a5abc6beff8 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1657,7 +1657,7 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val /* 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; + BKE_id_tag_set_atomic(id, LIB_TAG_ID_RECALC); DAG_id_type_tag(G.main, GS(id->name)); } } diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index c644fe09364..2b333941c6e 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1794,6 +1794,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected /* copy posechannel to temp, but restore important pointers */ pchanw = *pchanp; + pchanw.bone = pchan->bone; pchanw.prev = pchan->prev; pchanw.next = pchan->next; pchanw.parent = pchan->parent; @@ -1916,7 +1917,7 @@ void BKE_pose_clear_pointers(bPose *pose) /* only after leave editmode, duplicating, validating older files, library syncing */ /* NOTE: pose->flag is set for it */ -void BKE_pose_rebuild(Object *ob, bArmature *arm) +void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones) { Bone *bone; bPose *pose; @@ -1963,8 +1964,9 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) #ifdef WITH_LEGACY_DEPSGRAPH /* the sorting */ /* Sorting for new dependnecy graph is done on the scene graph level. */ - if (counter > 1) + if (counter > 1 && sort_bones) { DAG_pose_sort(ob); + } #endif ob->pose->flag &= ~POSE_RECALC; @@ -1973,6 +1975,11 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) BKE_pose_channels_hash_make(ob->pose); } +void BKE_pose_rebuild(Object *ob, bArmature *arm) +{ + BKE_pose_rebuild_ex(ob, arm, true); +} + /* ********************** THE POSE SOLVER ******************* */ /* loc/rot/size to given mat4 */ diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index a4c28121040..e57524af546 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -101,7 +101,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor IMB_colormanagement_check_file_config(bmain_dst); /* Append, rather than linking. */ Library *lib = BLI_findstring(&bmain_dst->library, libname, offsetof(Library, filepath)); - BKE_library_make_local(bmain_dst, lib, true, false); + BKE_library_make_local(bmain_dst, lib, NULL, true, false); /* Important we unset, otherwise these object wont * link into other scenes from this blend file. */ @@ -150,7 +150,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re /* append, rather than linking */ lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath)); - BKE_library_make_local(bmain, lib, true, false); + BKE_library_make_local(bmain, lib, NULL, true, false); /* important we unset, otherwise these object wont * link into other scenes from this blend file */ diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index d64bf7ecf43..ce6d29bbfee 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -319,6 +319,13 @@ const char *BKE_undo_get_name(int nr, bool *r_active) return NULL; } +/* return the name of the last item */ +const char *BKE_undo_get_name_last() +{ + UndoElem *uel = undobase.last; + return (uel ? uel->name : NULL); +} + /** * Saves .blend using undo buffer. * diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 6da68470ecc..54f709a1e5b 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -407,9 +407,9 @@ bool BKE_blendfile_read_from_memfile( if (bfd) { /* remove the unused screens and wm */ while (bfd->main->wm.first) - BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true); + BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true, true); while (bfd->main->screen.first) - BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true); + BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true, true); setup_app_data(C, bfd, "<memory1>", reports); } diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 6a08673144e..deeb35bd880 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -93,7 +93,9 @@ void BKE_cachefile_free(CacheFile *cache_file) ABC_free_handle(cache_file->handle); #endif - BLI_mutex_free(cache_file->handle_mutex); + if (cache_file->handle_mutex) { + BLI_mutex_free(cache_file->handle_mutex); + } BLI_freelistN(&cache_file->object_paths); } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 02ae123a71e..50f8423bbff 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -3284,7 +3284,7 @@ void DAG_threaded_update_handle_node_updated(void *node_v, for (itA = node->child; itA; itA = itA->next) { DagNode *child_node = itA->node; if (child_node != node) { - atomic_sub_uint32(&child_node->num_pending_parents, 1); + atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1); if (child_node->num_pending_parents == 0) { bool need_schedule; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index c7399047ed5..66070923153 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2264,7 +2264,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour). */ tPoint->neighbour_pixel = ind - 1; - atomic_add_uint32(&tPoint->neighbour_pixel, 1); + atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1); tPoint->tri_index = i; /* Now calculate pixel data for this pixel as it was on polygon surface */ @@ -2289,7 +2289,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in /* Increase the final number of active surface points if relevant. */ if (tPoint->tri_index != -1) - atomic_add_uint32(active_points, 1); + atomic_add_and_fetch_uint32(active_points, 1); } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 14612151a8e..3411eae22e1 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -73,6 +73,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_linklist.h" #include "BLI_memarena.h" @@ -128,6 +129,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "atomic_ops.h" + /* GS reads the memory pointed at in a specific ordering. * only use this definition, makes little and big endian systems * work fine, in conjunction with MAKE_ID */ @@ -261,9 +264,12 @@ void id_fake_user_clear(ID *id) } static int id_expand_local_callback( - void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag)) + void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag)) { - if (*id_pointer) { + /* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)... + * Just skip it, shape key can only be either indirectly linked, or fully local, period. + * And let's curse one more time that stupid useless shapekey ID type! */ + if (*id_pointer && *id_pointer != id_self && BKE_idcode_is_linkable(GS((*id_pointer)->name))) { id_lib_extern(*id_pointer); } @@ -1205,46 +1211,46 @@ void BKE_main_free(Main *mainvar) while ( (id = lb->first) ) { #if 1 - BKE_libblock_free_ex(mainvar, id, false); + BKE_libblock_free_ex(mainvar, id, false, false); #else /* errors freeing ID's can be hard to track down, * enable this so valgrind will give the line number in its error log */ switch (a) { - case 0: BKE_libblock_free_ex(mainvar, id, false); break; - case 1: BKE_libblock_free_ex(mainvar, id, false); break; - case 2: BKE_libblock_free_ex(mainvar, id, false); break; - case 3: BKE_libblock_free_ex(mainvar, id, false); break; - case 4: BKE_libblock_free_ex(mainvar, id, false); break; - case 5: BKE_libblock_free_ex(mainvar, id, false); break; - case 6: BKE_libblock_free_ex(mainvar, id, false); break; - case 7: BKE_libblock_free_ex(mainvar, id, false); break; - case 8: BKE_libblock_free_ex(mainvar, id, false); break; - case 9: BKE_libblock_free_ex(mainvar, id, false); break; - case 10: BKE_libblock_free_ex(mainvar, id, false); break; - case 11: BKE_libblock_free_ex(mainvar, id, false); break; - case 12: BKE_libblock_free_ex(mainvar, id, false); break; - case 13: BKE_libblock_free_ex(mainvar, id, false); break; - case 14: BKE_libblock_free_ex(mainvar, id, false); break; - case 15: BKE_libblock_free_ex(mainvar, id, false); break; - case 16: BKE_libblock_free_ex(mainvar, id, false); break; - case 17: BKE_libblock_free_ex(mainvar, id, false); break; - case 18: BKE_libblock_free_ex(mainvar, id, false); break; - case 19: BKE_libblock_free_ex(mainvar, id, false); break; - case 20: BKE_libblock_free_ex(mainvar, id, false); break; - case 21: BKE_libblock_free_ex(mainvar, id, false); break; - case 22: BKE_libblock_free_ex(mainvar, id, false); break; - case 23: BKE_libblock_free_ex(mainvar, id, false); break; - case 24: BKE_libblock_free_ex(mainvar, id, false); break; - case 25: BKE_libblock_free_ex(mainvar, id, false); break; - case 26: BKE_libblock_free_ex(mainvar, id, false); break; - case 27: BKE_libblock_free_ex(mainvar, id, false); break; - case 28: BKE_libblock_free_ex(mainvar, id, false); break; - case 29: BKE_libblock_free_ex(mainvar, id, false); break; - case 30: BKE_libblock_free_ex(mainvar, id, false); break; - case 31: BKE_libblock_free_ex(mainvar, id, false); break; - case 32: BKE_libblock_free_ex(mainvar, id, false); break; - case 33: BKE_libblock_free_ex(mainvar, id, false); break; - case 34: BKE_libblock_free_ex(mainvar, id, false); break; + case 0: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 1: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 2: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 3: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 4: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 5: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 6: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 7: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 8: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 9: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 10: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 11: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 12: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 13: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 14: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 15: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 16: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 17: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 18: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 19: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 20: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 21: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 22: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 23: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 24: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 25: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 26: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 27: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 28: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 29: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 30: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 31: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 32: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 33: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 34: BKE_libblock_free_ex(mainvar, id, false, false); break; default: BLI_assert(0); break; @@ -1626,30 +1632,28 @@ void BKE_main_id_clear_newpoins(Main *bmain) * \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING. * \param set_fake If true, set fake user on all localized datablocks (except group and objects ones). */ -/* XXX TODO This function should probably be reworked. - * - * Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether +/* Note: Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether * they were also indirectly used or not... * - * Current version uses regular id_make_local callback, but this is not super-efficient since this ends up + * Current version uses regular id_make_local callback, which is not super-efficient since this ends up * duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID). * - * We could first check all IDs and detect those to be made local that are only used by other local or future-local - * datablocks, and directly tag those as local (instead of going through id_make_local) maybe... - * - * We'll probably need at some point a true dependency graph between datablocks, but for now this should work - * good enough (performances is not a critical point here anyway). + * However, we now have a first check that allows us to use 'direct localization' of a lot of IDs, so performances + * are now *reasonably* OK. */ -void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake) +void BKE_library_make_local( + Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake) { ListBase *lbarray[MAX_LIBARRAY]; - ID *id, *id_next; + ID *id; int a; + LinkNode *todo_ids = NULL; LinkNode *copied_ids = NULL; LinkNode *linked_loop_candidates = NULL; - MemArena *linklist_mem = BLI_memarena_new(256 * sizeof(copied_ids), __func__); + MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__); + /* Step 1: Detect datablocks to make local. */ for (a = set_listbasepointers(bmain, lbarray); a--; ) { id = lbarray[a]->first; @@ -1657,54 +1661,80 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged * by real datablocks responsible of them. */ const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name))); - for (; id; id = id_next) { + for (; id; id = id->next) { id->newid = NULL; id->tag &= ~LIB_TAG_DOIT; - id_next = id->next; /* id is possibly being inserted again */ - /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its + if (id->lib == NULL) { + id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW); + } + /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its * possible to tag data you don't want to be made local, used for * appending data, so any libdata already linked wont become local - * (very nasty to discover all your links are lost after appending) - * */ - if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && - ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) + * (very nasty to discover all your links are lost after appending). + * Also, never ever make proxified objects local, would not make any sense. */ + else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && + ELEM(lib, NULL, id->lib) && + !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) && + ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) { - if (lib == NULL || id->lib == lib) { - if (id->lib) { - /* In this specific case, we do want to make ID local even if it has no local usage yet... */ - if (GS(id->name) == ID_OB) { - /* Special case for objects because we don't want proxy pointers to be - * cleared yet. This will happen down the road in this function. - */ - BKE_object_make_local_ex(bmain, (Object*)id, true, false); - } - else { - id_make_local(bmain, id, false, true); - } - - if (id->newid) { - BLI_linklist_prepend_arena(&copied_ids, id, linklist_mem); - } - } - else { - id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW); - } - } + BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem); + id->tag |= LIB_TAG_DOIT; + } + } + } - if (set_fake) { - if (!ELEM(GS(id->name), ID_OB, ID_GR)) { - /* do not set fake user on objects, groups (instancing) */ - id_fake_user_set(id); - } - } + /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future, + * local data), others will need to be duplicated and further processed later. */ + BKE_library_indirectly_used_data_tag_clear(bmain); + + /* Step 3: Make IDs local, either directly (quick and simple), or using generic process, + * which involves more complex checks and might instead create a local copy of original linked ID. */ + for (LinkNode *it = todo_ids, *it_next; it; it = it_next) { + it_next = it->next; + id = it->link; + + if (id->tag & LIB_TAG_DOIT) { + /* We know all users of this object are local or will be made fully local, even if currently there are + * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make + * that data block local. Saves a tremendous amount of time with complex scenes... */ + id_clear_lib_data_ex(bmain, id, true); + BKE_id_expand_local(id); + id->tag &= ~LIB_TAG_DOIT; + } + else { + /* In this specific case, we do want to make ID local even if it has no local usage yet... */ + if (GS(id->name) == ID_OB) { + /* Special case for objects because we don't want proxy pointers to be + * cleared yet. This will happen down the road in this function. + */ + BKE_object_make_local_ex(bmain, (Object*)id, true, false); + } + else { + id_make_local(bmain, id, false, true); + } + + if (id->newid) { + /* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */ + BLI_linklist_prepend_nlink(&copied_ids, id, it); + } + } + + if (set_fake) { + if (!ELEM(GS(id->name), ID_OB, ID_GR)) { + /* do not set fake user on objects, groups (instancing) */ + id_fake_user_set(id); } } } - /* We have to remap local usages of old (linked) ID to new (local) id in a second loop, as lbarray ordering is not - * enough to ensure us we did catch all dependencies (e.g. if making local a parent object before its child...). - * See T48907. */ + /* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their + * remaining linked original counterpart may not be needed anymore... */ + todo_ids = NULL; + + /* Step 4: We have to remap local usages of old (linked) ID to new (local) id in a separated loop, + * as lbarray ordering is not enough to ensure us we did catch all dependencies + * (e.g. if making local a parent object before its child...). See T48907. */ for (LinkNode *it = copied_ids; it; it = it->next) { id = it->link; @@ -1712,9 +1742,18 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged BLI_assert(id->lib != NULL); BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE); + if (old_to_new_ids) { + BLI_ghash_insert(old_to_new_ids, id, id->newid); + } + + /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure + * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */ + if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) { + id_us_ensure_real(id->newid); + } } - /* Third step: remove datablocks that have been copied to be localized and are no more used in the end... + /* Step 5: remove datablocks that have been copied to be localized and are no more used in the end... * Note that we may have to loop more than once here, to tackle dependencies between linked objects... */ bool do_loop = true; while (do_loop) { @@ -1761,11 +1800,6 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged ob->proxy = ob->proxy_from = ob->proxy_group = NULL; } } - /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure - * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */ - else if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) { - id_us_ensure_real(id->newid); - } if (!is_local) { if (!is_lib) { /* Not used at all, we can free it! */ @@ -1773,7 +1807,8 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged it->link = NULL; do_loop = true; } - else { /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */ + /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */ + else if ((id->tag & LIB_TAG_DOIT) == 0) { /* Check TAG_DOIT to avoid adding same ID several times... */ /* Note that we store the node, not directly ID pointer, that way if it->link is set to NULL * later we can skip it in lib-dependency cycles search later. */ BLI_linklist_prepend_arena(&linked_loop_candidates, it, linklist_mem); @@ -1791,9 +1826,9 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged } } - /* Fourth step: Try to find circle dependencies between indirectly-linked-only datablocks. + /* Step 6: Try to find circle dependencies between indirectly-linked-only datablocks. * Those are fake 'usages' that prevent their deletion. See T49775 for nice ugly case. */ - BKE_library_tag_unused_linked_data(bmain, false); + BKE_library_unused_linked_data_set_tag(bmain, false); for (LinkNode *it = linked_loop_candidates; it; it = it->next) { if (it->link == NULL) { continue; @@ -1806,16 +1841,23 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged /* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based * archipelagos, so no need to check again after we have deleted one, as done in previous step. */ if (id->tag & LIB_TAG_DOIT) { + /* Object's deletion rely on valid ob->data, but ob->data may have already been freed here... + * Setting it to NULL may not be 100% correct, but should be safe and do the work. */ + if (GS(id->name) == ID_OB) { + ((Object *)id)->data = NULL; + } + /* Note: *in theory* IDs tagged here are fully *outside* of file scope, totally unused, so we can * directly wipe them out without caring about clearing their usages. * However, this is a highly-risky presumption, and nice crasher in case something goes wrong here. * So for 2.78a will keep the safe option, and switch to more efficient one in master later. */ -#if 0 - BKE_libblock_free_ex(bmain, id, false); +#if 1 + BKE_libblock_free_ex(bmain, id, false, true); #else BKE_libblock_unlink(bmain, id, false, false); BKE_libblock_free(bmain, id); #endif + ((LinkNode *)it->link)->link = NULL; /* Not strictly necessary, but safer (see T49903)... */ it->link = NULL; } } @@ -1888,3 +1930,13 @@ void BKE_library_filepath_set(Library *lib, const char *filepath) BLI_path_abs(lib->filepath, basepath); } } + +void BKE_id_tag_set_atomic(ID *id, int tag) +{ + atomic_fetch_and_or_uint32((uint32_t *)&id->tag, tag); +} + +void BKE_id_tag_clear_atomic(ID *id, int tag) +{ + atomic_fetch_and_and_uint32((uint32_t *)&id->tag, ~tag); +} diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index cec7fbacd80..fa75c906fb1 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -1170,8 +1170,9 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo *is_used_linked = (iter.count_indirect != 0); } - -static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag)) +/* ***** IDs usages.checking/tagging. ***** */ +static int foreach_libblock_used_linked_data_tag_clear_cb( + void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag)) { bool *is_changed = user_data; @@ -1206,7 +1207,7 @@ static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID * \param do_init_tag if \a true, all linked data are checked, if \a false, only linked datablocks already tagged with * LIB_TAG_DOIT are checked. */ -void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag) +void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag) { ListBase *lb_array[MAX_LIBARRAY]; @@ -1232,7 +1233,38 @@ void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag) while (i--) { for (ID *id = lb_array[i]->first; id; id = id->next) { - BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP); + if (id->tag & LIB_TAG_DOIT) { + /* Unused ID (so far), no need to check it further. */ + continue; + } + BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP); + } + } + } +} + +/** + * Untag linked data blocks used by other untagged linked datablocks. + * Used to detect datablocks that we can forcefully make local (instead of copying them to later get rid of original): + * All datablocks we want to make local are tagged by caller, after this function has ran caller knows datablocks still + * tagged can directly be made local, since they are only used by other datablocks that will also be made fully local. + */ +void BKE_library_indirectly_used_data_tag_clear(Main *bmain) +{ + ListBase *lb_array[MAX_LIBARRAY]; + + bool do_loop = true; + while (do_loop) { + int i = set_listbasepointers(bmain, lb_array); + do_loop = false; + + while (i--) { + for (ID *id = lb_array[i]->first; id; id = id->next) { + if (id->lib == NULL || id->tag & LIB_TAG_DOIT) { + /* Local or non-indirectly-used ID (so far), no need to check it further. */ + continue; + } + BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP); } } } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index b468e6436c8..40441034171 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -666,46 +666,23 @@ void BKE_libblock_relink_ex( } } -static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) -{ - ChannelDriver *driver; - FCurve *fcu; - - /* find the driver this belongs to and update it */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - driver = fcu->driver; - - if (driver) { - DriverVar *dvar; - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - DRIVER_TARGETS_USED_LOOPER(dvar) - { - if (dtar->id == userdata) - dtar->id = NULL; - } - DRIVER_TARGETS_LOOPER_END - } - } - } -} - -void BKE_libblock_free_data(Main *bmain, ID *id) +void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id) { if (id->properties) { IDP_FreeProperty(id->properties); MEM_freeN(id->properties); } - - /* this ID may be a driver target! */ - BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); } /** * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c * * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv. + * (only applies to main database) + * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to + * \a id. */ -void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) +void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) { ID *id = idv; short type = GS(id->name); @@ -830,12 +807,14 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) /* avoid notifying on removed data */ BKE_main_lock(bmain); - if (free_notifier_reference_cb) { - free_notifier_reference_cb(id); - } + if (do_ui_user) { + if (free_notifier_reference_cb) { + free_notifier_reference_cb(id); + } - if (remap_editor_id_reference_cb) { - remap_editor_id_reference_cb(id, NULL); + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(id, NULL); + } } BLI_remlink(lb, id); @@ -848,7 +827,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) void BKE_libblock_free(Main *bmain, void *idv) { - BKE_libblock_free_ex(bmain, idv, true); + BKE_libblock_free_ex(bmain, idv, true, true); } void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index fa113ef5eef..a3fe73e4b11 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -58,6 +58,7 @@ #include "BLI_strict_flags.h" +#include "atomic_ops.h" #include "mikktspace.h" // #define DEBUG_TIME @@ -236,7 +237,9 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx) const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); /* accumulate */ - madd_v3_v3fl(vnors[ml[i].v], pnor, fac); + for (int k = 3; k--; ) { + atomic_add_and_fetch_fl(&vnors[ml[i].v][k], pnor[k] * fac); + } prev_edge = cur_edge; } } diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index b5f63588423..b5e1ded35bb 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -408,8 +408,9 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) /** * Remove all vgroups from object. Work in Object and Edit modes. + * When only_unlocked=true, locked vertex groups are not removed. */ -void BKE_object_defgroup_remove_all(Object *ob) +void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked) { bDeformGroup *dg = (bDeformGroup *)ob->defbase.first; const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob); @@ -418,10 +419,12 @@ void BKE_object_defgroup_remove_all(Object *ob) while (dg) { bDeformGroup *next_dg = dg->next; - if (edit_mode) - object_defgroup_remove_edit_mode(ob, dg); - else - object_defgroup_remove_object_mode(ob, dg); + if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) { + if (edit_mode) + object_defgroup_remove_edit_mode(ob, dg); + else + object_defgroup_remove_object_mode(ob, dg); + } dg = next_dg; } @@ -446,6 +449,15 @@ void BKE_object_defgroup_remove_all(Object *ob) } /** + * Remove all vgroups from object. Work in Object and Edit modes. + */ +void BKE_object_defgroup_remove_all(struct Object *ob) +{ + BKE_object_defgroup_remove_all_ex(ob, false); +} + + +/** * Get MDeformVert vgroup data from given object. Should only be used in Object mode. * * \return True if the id type supports weights. diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index ff69f381b06..4fe4d6e75a6 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -977,7 +977,7 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n) * Not exact equivalent though, since atomicity is only ensured for one component * of the vector at a time, but here it shall not make any sensible difference. */ for (int k = 3; k--; ) { - atomic_add_fl(&vnors[v][k], fn[k]); + atomic_add_and_fetch_fl(&vnors[v][k], fn[k]); } } } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 55f9f384081..a821578db1a 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -148,8 +148,7 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) * * Its assumed that \a l_radial_first is never forming the target face. */ -static bool bm_face_exists_tri_from_loop_vert( - BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing) +static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite) { BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v)); if (l_radial_first->radial_next != l_radial_first) { @@ -157,12 +156,11 @@ static bool bm_face_exists_tri_from_loop_vert( do { BLI_assert(l_radial_iter->f->len == 3); if (l_radial_iter->prev->v == v_opposite) { - *r_face_existing = l_radial_iter->f; - return true; + return l_radial_iter->f; } } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first); } - return false; + return NULL; } /** @@ -519,7 +517,7 @@ static BMFace *pbvh_bmesh_face_create( PBVHNode *node = &bvh->nodes[node_index]; /* ensure we never add existing face */ - BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); + BLI_assert(!BM_face_exists(v_tri, 3)); BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); f->head.hflag = f_example->head.hflag; @@ -1313,18 +1311,17 @@ static void pbvh_bmesh_collapse_edge( * deletion as well. Prevents extraneous "flaps" from being * created. */ #if 0 - if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face))) + if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3))) #else - if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face))) + if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn))) #endif { - BLI_assert(existing_face); BLI_buffer_append(deleted_faces, BMFace *, existing_face); } else { BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v}; - BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); + BLI_assert(!BM_face_exists(v_tri, 3)); BMEdge *e_tri[3]; PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f); int ni = n - bvh->nodes; diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index c3ae5736aa9..ebf9f017731 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -65,13 +65,22 @@ #include "BKE_rigidbody.h" #include "BKE_scene.h" -#ifdef WITH_BULLET - /* ************************************** */ /* Memory Management */ /* Freeing Methods --------------------- */ +#ifndef WITH_BULLET + +static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {} +static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {} +static void RB_dworld_delete(void *UNUSED(world)) {} +static void RB_body_delete(void *UNUSED(body)) {} +static void RB_shape_delete(void *UNUSED(shape)) {} +static void RB_constraint_delete(void *UNUSED(con)) {} + +#endif + /* Free rigidbody world */ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) { @@ -165,6 +174,8 @@ void BKE_rigidbody_free_constraint(Object *ob) ob->rigidbody_constraint = NULL; } +#ifdef WITH_BULLET + /* Copying Methods --------------------- */ /* These just copy the data, clearing out references to physics objects. @@ -804,6 +815,18 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z); RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z); + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x); + + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y); + + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); + RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); /* fall-through */ case RBC_TYPE_6DOF: @@ -1072,9 +1095,15 @@ RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short ty rbc->spring_damping_x = 0.5f; rbc->spring_damping_y = 0.5f; rbc->spring_damping_z = 0.5f; + rbc->spring_damping_ang_x = 0.5f; + rbc->spring_damping_ang_y = 0.5f; + rbc->spring_damping_ang_z = 0.5f; rbc->spring_stiffness_x = 10.0f; rbc->spring_stiffness_y = 10.0f; rbc->spring_stiffness_z = 10.0f; + rbc->spring_stiffness_ang_x = 10.0f; + rbc->spring_stiffness_ang_y = 10.0f; + rbc->spring_stiffness_ang_z = 10.0f; rbc->motor_lin_max_impulse = 1.0f; rbc->motor_lin_target_velocity = 1.0f; @@ -1602,9 +1631,6 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) # pragma GCC diagnostic ignored "-Wunused-parameter" #endif -void BKE_rigidbody_free_world(RigidBodyWorld *rbw) {} -void BKE_rigidbody_free_object(Object *ob) {} -void BKE_rigidbody_free_constraint(Object *ob) {} struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; } struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; } void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {} diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 05540f51588..e8970d416e9 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -360,6 +360,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd) BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); smd->domain->point_cache[0] = NULL; + if (smd->domain->coba) { + MEM_freeN(smd->domain->coba); + } + MEM_freeN(smd->domain); smd->domain = NULL; } @@ -544,6 +548,9 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->slice_depth = 0.5f; smd->domain->slice_axis = 0; smd->domain->vector_scale = 1.0f; + + smd->domain->coba = NULL; + smd->domain->coba_field = FLUID_FIELD_DENSITY; } else if (smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -646,6 +653,10 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData tsmd->domain->draw_velocity = smd->domain->draw_velocity; tsmd->domain->vector_draw_type = smd->domain->vector_draw_type; tsmd->domain->vector_scale = smd->domain->vector_scale; + + if (smd->domain->coba) { + tsmd->domain->coba = MEM_dupallocN(smd->domain->coba); + } } else if (tsmd->flow) { tsmd->flow->psys = smd->flow->psys; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 3132a8e27e7..f20885b1e8f 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -251,7 +251,8 @@ void BKE_sound_init(struct Main *bmain) void BKE_sound_init_main(struct Main *bmain) { #ifdef WITH_JACK - AUD_setSynchronizerCallback(sound_sync_callback, bmain); + if (sound_device) + AUD_setSynchronizerCallback(sound_sync_callback, bmain); #else (void)bmain; /* unused */ #endif diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 436cd2b8fde..fc2d9674c2f 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -237,7 +237,7 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done) BLI_assert(pool->num >= done); pool->num -= done; - atomic_sub_z(&pool->currently_running_tasks, done); + atomic_sub_and_fetch_z(&pool->currently_running_tasks, done); pool->done += done; if (pool->num == 0) @@ -292,7 +292,7 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task continue; } - if (atomic_add_z(&pool->currently_running_tasks, 1) <= pool->num_threads || + if (atomic_add_and_fetch_z(&pool->currently_running_tasks, 1) <= pool->num_threads || pool->num_threads == 0) { *task = current_task; @@ -301,7 +301,7 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task break; } else { - atomic_sub_z(&pool->currently_running_tasks, 1); + atomic_sub_and_fetch_z(&pool->currently_running_tasks, 1); } } if (!found_task) @@ -669,7 +669,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) /* if found task, do it, otherwise wait until other tasks are done */ if (found_task) { /* run task */ - atomic_add_z(&pool->currently_running_tasks, 1); + atomic_add_and_fetch_z(&pool->currently_running_tasks, 1); work_task->run(pool, work_task->taskdata, 0); /* delete task */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 0de883fe7bf..5c460c7b176 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5095,6 +5095,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) smd->domain->tex = NULL; smd->domain->tex_shadow = NULL; smd->domain->tex_wt = NULL; + smd->domain->coba = newdataadr(fd, smd->domain->coba); smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights); if (!smd->domain->effector_weights) diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 14e02c9ffb6..8133d0496fa 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -53,6 +53,7 @@ #include "DNA_actuator_types.h" #include "DNA_view3d_types.h" #include "DNA_smoke_types.h" +#include "DNA_rigidbody_types.h" #include "DNA_genfile.h" @@ -1426,7 +1427,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - { + if (!MAIN_VERSION_ATLEAST(main, 278, 3)) { for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) { if (scene->toolsettings != NULL) { ToolSettings *ts = scene->toolsettings; @@ -1438,5 +1439,31 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) { + Object *ob; + for (ob = main->object.first; ob; ob = ob->id.next) { + RigidBodyCon *rbc = ob->rigidbody_constraint; + if (rbc) { + rbc->spring_stiffness_ang_x = 10.0; + rbc->spring_stiffness_ang_y = 10.0; + rbc->spring_stiffness_ang_z = 10.0; + rbc->spring_damping_ang_x = 0.5; + rbc->spring_damping_ang_y = 0.5; + rbc->spring_damping_ang_z = 0.5; + } + } + } + + /* constant detail for sculpting is now a resolution value instead of + * a percentage, we reuse old DNA struct member but convert it */ + for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) { + if (scene->toolsettings != NULL) { + ToolSettings *ts = scene->toolsettings; + if (ts->sculpt && ts->sculpt->constant_detail != 0.0f) { + ts->sculpt->constant_detail = 100.0f / ts->sculpt->constant_detail; + } + } + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index b02b76118a2..f2fef5d476b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1729,6 +1729,10 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) smd->domain->point_cache[1]->step = 1; write_pointcaches(wd, &(smd->domain->ptcaches[1])); + + if (smd->domain->coba) { + writestruct(wd, DATA, ColorBand, 1, smd->domain->coba); + } } writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 72ea7bd7f5d..104df625ee6 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -245,7 +245,7 @@ typedef struct BMesh { /* ID of the shape key this bmesh came from */ int shapenr; - int walkers, totflags; + int totflags; ListBase selected; BMFace *act_face; diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 4d92baab6eb..132a7ccd4fa 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -626,7 +626,7 @@ void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void BM_elem_attrs_copy_ex(bm_src, bm_dst, ele_src, ele_dst, BM_ELEM_SELECT); } -void BM_elem_select_copy(BMesh *bm_dst, BMesh *UNUSED(bm_src), void *ele_dst_v, const void *ele_src_v) +void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v) { BMHeader *ele_dst = ele_dst_v; const BMHeader *ele_src = ele_src_v; diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index 06bc5465a19..9c6483de42b 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -58,7 +58,7 @@ void BM_elem_attrs_copy_ex( BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v, const char hflag_mask); void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v); -void BM_elem_select_copy(BMesh *bm_dst, BMesh *bm_src, void *ele_dst_v, const void *ele_src_v); +void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v); void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const struct BMAllocTemplate *allocsize); BMesh *BM_mesh_copy(BMesh *bm_old); diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index e83b752947c..0cd91107171 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -287,7 +287,7 @@ static BMLoop *bm_face_boundary_add( #endif BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag); - bmesh_radial_append(starte, l); + bmesh_radial_loop_append(starte, l); #ifdef USE_BMESH_HOLES lst->first = lst->last = l; @@ -295,8 +295,6 @@ static BMLoop *bm_face_boundary_add( #else f->l_first = l; #endif - - l->f = f; return l; } @@ -446,26 +444,20 @@ BMFace *BM_face_create( if (create_flag & BM_CREATE_NO_DOUBLE) { /* Check if face already exists */ - const bool is_overlap = BM_face_exists(verts, len, &f); - if (is_overlap) { + f = BM_face_exists(verts, len); + if (f != NULL) { return f; } - else { - BLI_assert(f == NULL); - } } f = bm_face_create__internal(bm); startl = lastl = bm_face_boundary_add(bm, f, verts[0], edges[0], create_flag); - - startl->v = verts[0]; - startl->e = edges[0]; + for (i = 1; i < len; i++) { l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag); - - l->f = f; - bmesh_radial_append(edges[i], l); + + bmesh_radial_loop_append(edges[i], l); l->prev = lastl; lastl->next = l; @@ -904,7 +896,7 @@ void BM_face_kill(BMesh *bm, BMFace *f) do { l_next = l_iter->next; - bmesh_radial_loop_remove(l_iter, l_iter->e); + bmesh_radial_loop_remove(l_iter->e, l_iter); bm_kill_only_loop(bm, l_iter); } while ((l_iter = l_next) != l_first); @@ -949,7 +941,7 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f) l_next = l_iter->next; e = l_iter->e; - bmesh_radial_loop_remove(l_iter, e); + bmesh_radial_loop_remove(e, l_iter); bm_kill_only_loop(bm, l_iter); if (e->l == NULL) { @@ -981,23 +973,8 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f) */ void BM_edge_kill(BMesh *bm, BMEdge *e) { - - if (e->l) { - BMLoop *l = e->l, *lnext, *startl = e->l; - - do { - lnext = l->radial_next; - if (lnext->f == l->f) { - BM_face_kill(bm, l->f); - break; - } - - BM_face_kill(bm, l->f); - - if (l == lnext) - break; - l = lnext; - } while (l != startl); + while (e->l) { + BM_face_kill(bm, e->l->f); } bmesh_disk_edge_remove(e, e->v1); @@ -1011,15 +988,8 @@ void BM_edge_kill(BMesh *bm, BMEdge *e) */ void BM_vert_kill(BMesh *bm, BMVert *v) { - if (v->e) { - BMEdge *e, *e_next; - - e = v->e; - while (v->e) { - e_next = bmesh_disk_edge_next(e, v); - BM_edge_kill(bm, e); - e = e_next; - } + while (v->e) { + BM_edge_kill(bm, v->e); } bm_kill_only_vert(bm, v); @@ -1046,78 +1016,73 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l) * \brief Loop Reverse * * Changes the winding order of a face from CW to CCW or vice versa. - * This euler is a bit peculiar in comparison to others as it is its - * own inverse. - * - * BMESH_TODO: reinsert validation code. * * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`. * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp, * (use when flipping normals, disable when mirroring, eg: symmetrize). - * - * \return Success */ -static bool bm_loop_reverse_loop( +void bmesh_loop_reverse( BMesh *bm, BMFace *f, -#ifdef USE_BMESH_HOLES - BMLoopList *lst, -#endif const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) { + BMLoop *l_first = f->l_first; -#ifdef USE_BMESH_HOLES - BMLoop *l_first = lst->first; + /* track previous cycles radial state */ + BMEdge *e_prev = l_first->prev->e; + BMLoop *l_prev_radial_next = l_first->prev->radial_next; + BMLoop *l_prev_radial_prev = l_first->prev->radial_prev; + bool is_prev_boundary = l_prev_radial_next == l_prev_radial_next->radial_next; + + BMLoop *l_iter = l_first; + do { + BMEdge *e_iter = l_iter->e; + BMLoop *l_iter_radial_next = l_iter->radial_next; + BMLoop *l_iter_radial_prev = l_iter->radial_prev; + bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next; + +#if 0 + bmesh_radial_loop_remove(e_iter, l_iter); + bmesh_radial_loop_append(e_prev, l_iter); #else - BMLoop *l_first = f->l_first; -#endif + /* inline loop reversal */ + if (is_prev_boundary) { + /* boundary */ + l_iter->radial_next = l_iter; + l_iter->radial_prev = l_iter; + } + else { + /* non-boundary, replace radial links */ + l_iter->radial_next = l_prev_radial_next; + l_iter->radial_prev = l_prev_radial_prev; + l_prev_radial_next->radial_prev = l_iter; + l_prev_radial_prev->radial_next = l_iter; + } - const int len = f->len; - BMLoop *l_iter, *oldprev, *oldnext; - BMEdge **edar = BLI_array_alloca(edar, len); - int i, j, edok; + if (e_iter->l == l_iter) { + e_iter->l = l_iter->next; + } + l_iter->e = e_prev; +#endif - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { - bmesh_radial_loop_remove(l_iter, (edar[i] = l_iter->e)); - } + SWAP(BMLoop *, l_iter->next, l_iter->prev); - /* actually reverse the loop */ - for (i = 0, l_iter = l_first; i < len; i++) { - oldnext = l_iter->next; - oldprev = l_iter->prev; - l_iter->next = oldprev; - l_iter->prev = oldnext; - l_iter = oldnext; - if (cd_loop_mdisp_offset != -1) { MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset); BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip); } - } - if (len == 2) { /* two edged face */ - /* do some verification here! */ - l_first->e = edar[1]; - l_first->next->e = edar[0]; - } - else { - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { - edok = 0; - for (j = 0; j < len; j++) { - edok = BM_verts_in_edge(l_iter->v, l_iter->next->v, edar[j]); - if (edok) { - l_iter->e = edar[j]; - break; - } - } - } - } - /* rebuild radial */ - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) - bmesh_radial_append(l_iter->e, l_iter); + e_prev = e_iter; + l_prev_radial_next = l_iter_radial_next; + l_prev_radial_prev = l_iter_radial_prev; + is_prev_boundary = is_iter_boundary; + + /* step to next (now swapped) */ + } while ((l_iter = l_iter->prev) != l_first); #ifndef NDEBUG /* validate radial */ - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { + int i; + for (i = 0, l_iter = l_first; i < f->len; i++, l_iter = l_iter->next) { BM_CHECK_ELEMENT(l_iter); BM_CHECK_ELEMENT(l_iter->e); BM_CHECK_ELEMENT(l_iter->v); @@ -1129,22 +1094,6 @@ static bool bm_loop_reverse_loop( /* Loop indices are no more valid! */ bm->elem_index_dirty |= BM_LOOP; - - return true; -} - -/** - * \brief Flip the faces direction - */ -bool bmesh_loop_reverse( - BMesh *bm, BMFace *f, - const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) -{ -#ifdef USE_BMESH_HOLES - return bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip); -#else - return bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); -#endif } static void bm_elements_systag_enable(void *veles, int tot, const char api_flag) @@ -1193,7 +1142,11 @@ static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_ return i; } -static bool disk_is_flagged(BMVert *v, const char api_flag) +/** + * Return true when the vertex is manifold, + * attached to faces which are all flagged. + */ +static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag) { BMEdge *e = v->e; @@ -1252,7 +1205,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) BLI_array_staticdeclare(deledges, BM_DEFAULT_NGON_STACK_SIZE); BLI_array_staticdeclare(delverts, BM_DEFAULT_NGON_STACK_SIZE); BMVert *v1 = NULL, *v2 = NULL; - int i, tote = 0; + int i; const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); if (UNLIKELY(!totface)) { @@ -1282,13 +1235,10 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) v1 = l_iter->v; v2 = BM_edge_other_vert(l_iter->e, l_iter->v); } - tote++; } else if (rlen == 2) { - int d1, d2; - - d1 = disk_is_flagged(l_iter->e->v1, _FLAG_JF); - d2 = disk_is_flagged(l_iter->e->v2, _FLAG_JF); + const bool d1 = bm_vert_is_manifold_flagged(l_iter->e->v1, _FLAG_JF); + const bool d2 = bm_vert_is_manifold_flagged(l_iter->e->v2, _FLAG_JF); if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) { /* don't remove an edge it makes up the side of another face @@ -1332,7 +1282,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) } /* create region face */ - f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, faces[0], BM_CREATE_NOP) : NULL; + f_new = BLI_array_count(edges) ? + BM_face_create_ngon(bm, v1, v2, edges, BLI_array_count(edges), faces[0], BM_CREATE_NOP) : NULL; if (UNLIKELY(f_new == NULL)) { /* Invalid boundary region to join faces */ goto error; @@ -1350,10 +1301,11 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) } while (l2 != l_iter); if (l2 != l_iter) { - /* I think this is correct? */ + /* loops share an edge, shared vert depends on winding */ if (l2->v != l_iter->v) { l2 = l2->next; } + BLI_assert(l_iter->v == l2->v); BM_elem_attrs_copy(bm, bm, l2, l_iter); } @@ -1362,22 +1314,15 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) #ifdef USE_BMESH_HOLES /* add holes */ BLI_movelisttolist(&f_new->loops, &holes); -#endif /* update loop face pointer */ -#ifdef USE_BMESH_HOLES - for (lst = f_new->loops.first; lst; lst = lst->next) -#endif - { -#ifdef USE_BMESH_HOLES + for (lst = f_new->loops.first; lst; lst = lst->next) { l_iter = l_first = lst->first; -#else - l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); -#endif do { l_iter->f = f_new; } while ((l_iter = l_iter->next) != l_first); } +#endif bm_elements_systag_disable(faces, totface, _FLAG_JF); BM_ELEM_API_FLAG_DISABLE(f_new, _FLAG_JF); @@ -1585,8 +1530,8 @@ BMFace *bmesh_sfme( } while ((l_iter = l_iter->next) != l_first); /* link up the new loops into the new edges radial */ - bmesh_radial_append(e, l_f1); - bmesh_radial_append(e, l_f2); + bmesh_radial_loop_append(e, l_f1); + bmesh_radial_loop_append(e, l_f2); f2->len = f2len; @@ -1693,18 +1638,18 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) #ifndef NDEBUG int radlen = bmesh_radial_length(l_next); #endif - int first1 = 0, first2 = 0; + bool is_first = true; /* Take the next loop. Remove it from radial. Split it. Append to appropriate radials */ while (l_next) { l = l_next; l->f->len++; l_next = l_next != l_next->radial_next ? l_next->radial_next : NULL; - bmesh_radial_loop_remove(l, NULL); + bmesh_radial_loop_unlink(l); l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0); l_new->prev = l; - l_new->next = (l->next); + l_new->next = l->next; l_new->prev->next = l_new; l_new->next->prev = l_new; l_new->v = v_new; @@ -1715,36 +1660,26 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l->e = e_new; /* append l into e_new's rad cycle */ - if (!first1) { - first1 = 1; - l->radial_next = l->radial_prev = NULL; - } - - if (!first2) { - first2 = 1; + if (is_first) { + is_first = false; l->radial_next = l->radial_prev = NULL; } - bmesh_radial_append(l_new->e, l_new); - bmesh_radial_append(l->e, l); + bmesh_radial_loop_append(l_new->e, l_new); + bmesh_radial_loop_append(l->e, l); } else if (BM_verts_in_edge(l_new->v, l_new->next->v, e_new)) { l_new->e = e_new; l->e = e; /* append l into e_new's rad cycle */ - if (!first1) { - first1 = 1; + if (is_first) { + is_first = false; l->radial_next = l->radial_prev = NULL; } - if (!first2) { - first2 = 1; - l->radial_next = l->radial_prev = NULL; - } - - bmesh_radial_append(l_new->e, l_new); - bmesh_radial_append(l->e, l); + bmesh_radial_loop_append(l_new->e, l_new); + bmesh_radial_loop_append(l->e, l); } } @@ -1839,7 +1774,6 @@ BMEdge *bmesh_jekv( BMEdge *e_old; BMVert *v_old, *v_target; BMLoop *l_kill; - bool halt = false; #ifndef NDEBUG int radlen, i; bool edok; @@ -1860,9 +1794,9 @@ BMEdge *bmesh_jekv( e_old = bmesh_disk_edge_next(e_kill, v_kill); v_target = BM_edge_other_vert(e_kill, v_kill); v_old = BM_edge_other_vert(e_old, v_kill); - halt = BM_verts_in_edge(v_kill, v_target, e_old); /* check for double edges */ - - if (halt) { + + /* check for double edges */ + if (BM_verts_in_edge(v_kill, v_target, e_old)) { return NULL; } else { @@ -2413,7 +2347,7 @@ void bmesh_vert_separate( v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); if (copy_select) { - BM_elem_select_copy(bm, bm, v_new, v); + BM_elem_select_copy(bm, v_new, v); } while ((e = BLI_SMALLSTACK_POP(edges))) { @@ -2471,18 +2405,13 @@ static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate) do { BMEdge *e_orig = n_orig->link; LinkNode *n_step = n_orig->next; - LinkNode *n_prev = n_orig; do { BMEdge *e = n_step->link; BLI_assert(e != e_orig); if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) { BM_edge_splice(bm, e_orig, e); - n_prev->next = n_step->next; - n_step = n_prev; } - } while ((void) - (n_prev = n_step), - (n_step = n_step->next)); + } while ((n_step = n_step->next)); } while ((n_orig = n_orig->next) && n_orig->next); } while ((edges_separate = edges_separate->next)); @@ -2619,8 +2548,8 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src) l = e_src->l; BLI_assert(BM_vert_in_edge(e_dst, l->v)); BLI_assert(BM_vert_in_edge(e_dst, l->next->v)); - bmesh_radial_loop_remove(l, e_src); - bmesh_radial_append(e_dst, l); + bmesh_radial_loop_remove(e_src, l); + bmesh_radial_loop_append(e_dst, l); } BLI_assert(bmesh_radial_length(e_src->l) == 0); @@ -2667,12 +2596,12 @@ void bmesh_edge_separate( } e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP); - bmesh_radial_loop_remove(l_sep, e); - bmesh_radial_append(e_new, l_sep); + bmesh_radial_loop_remove(e, l_sep); + bmesh_radial_loop_append(e_new, l_sep); l_sep->e = e_new; if (copy_select) { - BM_elem_select_copy(bm, bm, e_new, e); + BM_elem_select_copy(bm, e_new, e); } BLI_assert(bmesh_radial_length(e->l) == radlen - 1); @@ -2855,8 +2784,8 @@ BMVert *bmesh_urmv_loop_multi( do { l_next = l_iter->radial_next; if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) { - bmesh_radial_loop_remove(l_iter, e); - bmesh_radial_append(e_new, l_iter); + bmesh_radial_loop_remove(e, l_iter); + bmesh_radial_loop_append(e_new, l_iter); l_iter->e = e_new; } } while ((l_iter = l_next) != l_first); diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h index fb5702bc574..f72e9d7b198 100644 --- a/source/blender/bmesh/intern/bmesh_core.h +++ b/source/blender/bmesh/intern/bmesh_core.h @@ -75,7 +75,7 @@ void bmesh_vert_separate( BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select); -bool bmesh_loop_reverse( +void bmesh_loop_reverse( BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip); diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index 961b10d848a..96154f051f9 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -485,9 +485,9 @@ void bmiter__face_of_vert_begin(struct BMIter__face_of_vert *iter) { ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata); if (((BMIter *)iter)->count) { - iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata); + iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata); + iter->e_first = iter->l_first->e; iter->e_next = iter->e_first; - iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata); iter->l_next = iter->l_first; } else { @@ -526,9 +526,9 @@ void bmiter__loop_of_vert_begin(struct BMIter__loop_of_vert *iter) { ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata); if (((BMIter *)iter)->count) { - iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata); + iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata); + iter->e_first = iter->l_first->e; iter->e_next = iter->e_first; - iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata); iter->l_next = iter->l_first; } else { diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index d3c847de64e..03165beb329 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -104,7 +104,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v) */ bool BM_disk_dissolve(BMesh *bm, BMVert *v) { - BMFace *f, *f2; BMEdge *e, *keepedge = NULL, *baseedge = NULL; int len = 0; @@ -132,16 +131,17 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) #if 0 /* handle specific case for three-valence. solve it by * increasing valence to four. this may be hackish. . */ - BMLoop *loop = e->l; - if (loop->v == v) loop = loop->next; - if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL, false)) + BMLoop *l_a = BM_face_vert_share_loop(e->l->f, v); + BMLoop *l_b = (e->l->v == v) ? e->l->next : e->l; + + if (!BM_face_split(bm, e->l->f, l_a, l_b, NULL, NULL, false)) return false; if (!BM_disk_dissolve(bm, v)) { return false; } #else - if (UNLIKELY(!BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true))) { + if (UNLIKELY(!BM_faces_join_pair(bm, e->l, e->l->radial_next, true))) { return false; } else if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true))) { @@ -159,11 +159,10 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) } /* handle two-valence */ - f = e->l->f; - f2 = e->l->radial_next->f; - - if (f != f2 && !BM_faces_join_pair(bm, f, f2, e, true)) { - return false; + if (e->l != e->l->radial_next) { + if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) { + return false; + } } return true; @@ -176,9 +175,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) done = true; e = v->e; do { - f = NULL; + BMFace *f = NULL; if (BM_edge_is_manifold(e) && (e != baseedge) && (e != keepedge)) { - f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true); + f = BM_faces_join_pair(bm, e->l, e->l->radial_next, true); /* return if couldn't join faces in manifold * conditions */ /* !disabled for testing why bad things happen */ @@ -204,12 +203,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) if (e->l) { /* get remaining two faces */ - f = e->l->f; - f2 = e->l->radial_next->f; - - if (f != f2) { + if (e->l != e->l->radial_next) { /* join two remaining faces */ - if (!BM_faces_join_pair(bm, f, f2, e, true)) { + if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) { return false; } } @@ -224,30 +220,24 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) * * Joins two adjacent faces together. * - * Because this method calls to #BM_faces_join to do its work, if a pair - * of faces share multiple edges, the pair of faces will be joined at - * every edge (not just edge \a e). This part of the functionality might need - * to be reconsidered. + * \note This method calls to #BM_faces_join to do its work. + * This means connected edges which also share the two faces will be joined. * * If the windings do not match the winding of the new face will follow - * \a f_a's winding (i.e. \a f_b will be reversed before the join). + * \a l_a's winding (i.e. \a l_b will be reversed before the join). * - * \return pointer to the combined face + * \return The combined face or NULL on failure. */ -BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const bool do_del) +BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del) { - BMFace *faces[2] = {f_a, f_b}; - - BMLoop *l_a = BM_face_edge_share_loop(f_a, e); - BMLoop *l_b = BM_face_edge_share_loop(f_b, e); - - BLI_assert(l_a && l_b); + BLI_assert((l_a != l_b) && (l_a->e == l_b->e)); if (l_a->v == l_b->v) { const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - bmesh_loop_reverse(bm, f_b, cd_loop_mdisp_offset, true); + bmesh_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true); } - + + BMFace *faces[2] = {l_a->f, l_b->f}; return BM_faces_join(bm, faces, 2, do_del); } @@ -551,7 +541,7 @@ BMEdge *BM_vert_collapse_edge( BMVert *tv2 = BM_edge_other_vert(e2, v_kill); if (tv2) { /* only action, other calls here only get the edge to return */ - e_new = bmesh_jekv(bm, e_kill, v_kill, do_del); + e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces); } } } @@ -598,18 +588,13 @@ BMVert *BM_edge_collapse( BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) { BMVert *v_new, *v_other; + BMEdge *e_new; BMFace **oldfaces = NULL; - BMEdge *e_dummy; BLI_array_staticdeclare(oldfaces, 32); const int cd_loop_mdisp_offset = BM_edge_is_wire(e) ? -1 : CustomData_get_offset(&bm->ldata, CD_MDISPS); BLI_assert(BM_vert_in_edge(e, v) == true); - /* we need this for handling multi-res */ - if (!r_e) { - r_e = &e_dummy; - } - /* do we have a multi-res layer? */ if (cd_loop_mdisp_offset != -1) { BMLoop *l; @@ -630,17 +615,20 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) } v_other = BM_edge_other_vert(e, v); - v_new = bmesh_semv(bm, v, e, r_e); + v_new = bmesh_semv(bm, v, e, &e_new); + if (r_e != NULL) { + *r_e = e_new; + } BLI_assert(v_new != NULL); - BLI_assert(BM_vert_in_edge(*r_e, v) && BM_vert_in_edge(*r_e, v_new)); + BLI_assert(BM_vert_in_edge(e_new, v) && BM_vert_in_edge(e_new, v_new)); BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other)); sub_v3_v3v3(v_new->co, v_other->co, v->co); madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac); - (*r_e)->head.hflag = e->head.hflag; - BM_elem_attrs_copy(bm, bm, e, *r_e); + e_new->head.hflag = e->head.hflag; + BM_elem_attrs_copy(bm, bm, e, e_new); /* v->v_new->v2 */ BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac); @@ -656,7 +644,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) BM_face_calc_center_mean(oldfaces[i], f_center_old); for (j = 0; j < 2; j++) { - BMEdge *e1 = j ? *r_e : e; + BMEdge *e1 = j ? e_new : e; BMLoop *l; l = e1->l; @@ -689,7 +677,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) /* fix boundaries a bit, doesn't work too well quite yet */ #if 0 for (j = 0; j < 2; j++) { - BMEdge *e1 = j ? *r_e : e; + BMEdge *e1 = j ? e_new : e; BMLoop *l, *l2; l = e1->l; @@ -991,6 +979,7 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f BMLoop *l1, *l2; BMFace *f; BMEdge *e_new = NULL; + char f_active_prev = 0; char f_hflag_prev_1; char f_hflag_prev_2; @@ -1041,8 +1030,18 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f f_hflag_prev_1 = l1->f->head.hflag; f_hflag_prev_2 = l2->f->head.hflag; + /* maintain active face */ + if (bm->act_face == l1->f) { + f_active_prev = 1; + } + else if (bm->act_face == l2->f) { + f_active_prev = 2; + } + + const bool is_flipped = !BM_edge_is_contiguous(e); + /* don't delete the edge, manually remove the edge after so we can copy its attributes */ - f = BM_faces_join_pair(bm, l1->f, l2->f, e, true); + f = BM_faces_join_pair(bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true); if (f == NULL) { return NULL; @@ -1062,6 +1061,22 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f if (BM_edge_face_pair(e_new, &fa, &fb)) { fa->head.hflag = f_hflag_prev_1; fb->head.hflag = f_hflag_prev_2; + + if (f_active_prev == 1) { + bm->act_face = fa; + } + else if (f_active_prev == 2) { + bm->act_face = fb; + } + + if (is_flipped) { + BM_face_normal_flip(bm, fb); + + if (ccw) { + /* needed otherwise ccw toggles direction */ + e_new->l = e_new->l->radial_next; + } + } } } else { diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h index 2e557e3b606..5e95e9a2cc7 100644 --- a/source/blender/bmesh/intern/bmesh_mods.h +++ b/source/blender/bmesh/intern/bmesh_mods.h @@ -31,7 +31,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v); bool BM_disk_dissolve(BMesh *bm, BMVert *v); -BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del); +BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del); /** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */ diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index b5f9575aff5..7ca5640578a 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -102,17 +102,10 @@ BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) */ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) { - BMIter liter; - BMLoop *l_iter; + BMLoop *l_iter = BM_face_vert_share_loop(f, v); BLI_assert(BM_edge_exists(v_prev, v) != NULL); - BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) { - if (l_iter->f == f) { - break; - } - } - if (l_iter) { if (l_iter->prev->v == v_prev) { return l_iter->next; @@ -149,7 +142,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) * The faces loop direction is ignored. * </pre> */ - BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) { #if 0 /* works but slow */ @@ -178,9 +170,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) return l->next->next; } } - - - #endif } @@ -392,17 +381,7 @@ BMFace *BM_vert_pair_share_face_by_angle( */ BMLoop *BM_vert_find_first_loop(BMVert *v) { - BMEdge *e; - - if (!v->e) - return NULL; - - e = bmesh_disk_faceedge_find_first(v->e, v); - - if (!e) - return NULL; - - return bmesh_radial_faceloop_find_first(e->l, v); + return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL; } /** @@ -878,9 +857,18 @@ int BM_vert_face_count_ex(const BMVert *v, int count_max) * * same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL`` */ -bool BM_vert_face_check(BMVert *v) +bool BM_vert_face_check(const BMVert *v) { - return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL); + if (v->e != NULL) { + const BMEdge *e_iter, *e_first; + e_first = e_iter = v->e; + do { + if (e_iter->l != NULL) { + return true; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first); + } + return false; } /** @@ -910,7 +898,7 @@ bool BM_vert_is_wire(const BMVert *v) * A vertex is non-manifold if it meets the following conditions: * 1: Loose - (has no edges/faces incident upon it). * 2: Joins two distinct regions - (two pyramids joined at the tip). - * 3: Is part of a an edge with more than 2 faces. + * 3: Is part of an edge with more than 2 faces. * 4: Is part of a wire edge. */ bool BM_vert_is_manifold(const BMVert *v) @@ -926,7 +914,8 @@ bool BM_vert_is_manifold(const BMVert *v) /* count edges while looking for non-manifold edges */ e_first = e_iter = v->e; - l_first = e_iter->l ? e_iter->l : NULL; + /* may be null */ + l_first = e_iter->l; do { /* loose edge or edge shared by more than two faces, * edges with 1 face user are OK, otherwise we could @@ -1924,7 +1913,7 @@ BMEdge *BM_edge_find_double(BMEdge *e) * * \note there used to be a BM_face_exists_overlap function that checks for partial overlap. */ -bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) +BMFace *BM_face_exists(BMVert **varr, int len) { if (varr[0]->e) { BMEdge *e_iter, *e_first; @@ -1963,10 +1952,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) } if (i_walk == len) { - if (r_existface) { - *r_existface = l_iter_radial->f; - } - return true; + return l_iter_radial->f; } } } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial); @@ -1975,10 +1961,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first); } - if (r_existface) { - *r_existface = NULL; - } - return false; + return NULL; } @@ -2121,26 +2104,21 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len) * \note The face may contain other verts \b not in \a varr. * * \note Its possible there are more than one overlapping faces, - * in this case the first one found will be assigned to \a r_f_overlap. + * in this case the first one found will be returned. * * \param varr Array of unordered verts. * \param len \a varr array length. - * \param r_f_overlap The overlapping face to return. - * \return Success + * \return The face or NULL. */ -bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) +BMFace *BM_face_exists_overlap(BMVert **varr, const int len) { BMIter viter; BMFace *f; int i; - bool is_overlap = false; + BMFace *f_overlap = NULL; LinkNode *f_lnk = NULL; - if (r_f_overlap) { - *r_f_overlap = NULL; - } - #ifdef DEBUG /* check flag isn't already set */ for (i = 0; i < len; i++) { @@ -2154,10 +2132,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) { if (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0) { if (len <= BM_verts_in_face_count(varr, len, f)) { - if (r_f_overlap) - *r_f_overlap = f; - - is_overlap = true; + f_overlap = f; break; } @@ -2171,7 +2146,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) BM_ELEM_API_FLAG_DISABLE((BMFace *)f_lnk->link, _FLAG_OVERLAP); } - return is_overlap; + return f_overlap; } /** diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 10e4b9a15aa..a6a37767ee9 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -86,7 +86,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT AT bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b); -bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -135,12 +135,12 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) ATTR_NONNULL(1); +BMFace* BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1); bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT; bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index cb302139a4c..8e484841568 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -143,7 +143,7 @@ void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) * to store non-manifold conditions since BM does not keep track of region/shell information. * * Functions relating to this cycle: - * - #bmesh_radial_append + * - #bmesh_radial_loop_append * - #bmesh_radial_loop_remove * - #bmesh_radial_facevert_count * - #bmesh_radial_facevert_check @@ -264,10 +264,12 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v) { BMEdge *e_iter; - if (!BM_vert_in_edge(e, v)) + if (!BM_vert_in_edge(e, v)) { return false; - if (bmesh_disk_count_ex(v, len + 1) != len || len == 0) + } + if (len == 0 || bmesh_disk_count_ex(v, len + 1) != len) { return false; + } e_iter = e; do { @@ -336,13 +338,28 @@ int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) */ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) { - const BMEdge *e_find = e; + const BMEdge *e_iter = e; do { - if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) { - return (BMEdge *)e_find; + if (e_iter->l != NULL) { + return (BMEdge *)((e_iter->l->v == v) ? e_iter : e_iter->l->next->e); } - } while ((e_find = bmesh_disk_edge_next(e_find, v)) != e); + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e); + return NULL; +} +/** + * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls. + * + * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first + */ +BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) +{ + const BMEdge *e_iter = e; + do { + if (e_iter->l != NULL) { + return (e_iter->l->v == v) ? e_iter->l : e_iter->l->next; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e); return NULL; } @@ -389,6 +406,30 @@ bool bmesh_radial_validate(int radlen, BMLoop *l) return true; } +void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) +{ + if (e->l == NULL) { + e->l = l; + l->radial_next = l->radial_prev = l; + } + else { + l->radial_prev = e->l; + l->radial_next = e->l->radial_next; + + e->l->radial_next->radial_prev = l; + e->l->radial_next = l; + + e->l = l; + } + + if (UNLIKELY(l->e && l->e != e)) { + /* l is already in a radial cycle for a different edge */ + BMESH_ASSERT(0); + } + + l->e = e; +} + /** * \brief BMESH RADIAL REMOVE LOOP * @@ -397,28 +438,27 @@ bool bmesh_radial_validate(int radlen, BMLoop *l) * updated (in the case that the edge's link into the radial * cycle was the loop which is being removed from the cycle). */ -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) +void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) { /* if e is non-NULL, l must be in the radial cycle of e */ - if (UNLIKELY(e && e != l->e)) { + if (UNLIKELY(e != l->e)) { BMESH_ASSERT(0); } if (l->radial_next != l) { - if (e && l == e->l) + if (l == e->l) { e->l = l->radial_next; + } l->radial_next->radial_prev = l->radial_prev; l->radial_prev->radial_next = l->radial_next; } else { - if (e) { - if (l == e->l) { - e->l = NULL; - } - else { - BMESH_ASSERT(0); - } + if (l == e->l) { + e->l = NULL; + } + else { + BMESH_ASSERT(0); } } @@ -428,6 +468,22 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) l->e = NULL; } +/** + * A version of #bmesh_radial_loop_remove which only performs the radial unlink, + * leaving the edge untouched. + */ +void bmesh_radial_loop_unlink(BMLoop *l) +{ + if (l->radial_next != l) { + l->radial_next->radial_prev = l->radial_prev; + l->radial_prev->radial_next = l->radial_next; + } + + /* l is no longer in a radial cycle; empty the links + * to the cycle and the link back to an edge */ + l->radial_next = l->radial_prev = NULL; + l->e = NULL; +} /** * \brief BME RADIAL FIND FIRST FACE VERT @@ -484,30 +540,6 @@ int bmesh_radial_length(const BMLoop *l) return i; } -void bmesh_radial_append(BMEdge *e, BMLoop *l) -{ - if (e->l == NULL) { - e->l = l; - l->radial_next = l->radial_prev = l; - } - else { - l->radial_prev = e->l; - l->radial_next = e->l->radial_next; - - e->l->radial_next->radial_prev = l; - e->l->radial_next = l; - - e->l = l; - } - - if (UNLIKELY(l->e && l->e != e)) { - /* l is already in a radial cycle for a different edge */ - BMESH_ASSERT(0); - } - - l->e = e; -} - /** * \brief RADIAL COUNT FACE VERT * diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h index 07f94796bb2..0efb25da37c 100644 --- a/source/blender/bmesh/intern/bmesh_structure.h +++ b/source/blender/bmesh/intern/bmesh_structure.h @@ -52,11 +52,13 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* RADIAL CYCLE MANAGMENT */ -void bmesh_radial_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1); +void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL(); /* note: * bmesh_radial_loop_next(BMLoop *l) / prev. * just use member access l->radial_next, l->radial_prev now */ diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 6ef0fd6b084..61179d7be70 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -398,7 +398,8 @@ static void bridge_loop_pair( if (v_b != v_b_next) { BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next}; - if (BM_face_exists(v_arr, 4, &f) == false) { + f = BM_face_exists(v_arr, 4); + if (f == NULL) { /* copy if loop data if its is missing on one ring */ f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true); @@ -411,7 +412,8 @@ static void bridge_loop_pair( } else { BMVert *v_arr[3] = {v_a, v_b, v_a_next}; - if (BM_face_exists(v_arr, 3, &f) == false) { + f = BM_face_exists(v_arr, 3); + if (f == NULL) { /* fan-fill a triangle */ f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true); diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 05efb14a699..6e3a8a1473d 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -322,12 +322,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) } BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) { - BMFace *fa, *fb; - if (BM_edge_face_pair(e, &fa, &fb)) { + BMLoop *l_a, *l_b; + if (BM_edge_loop_pair(e, &l_a, &l_b)) { BMFace *f_new; /* join faces */ - f_new = BM_faces_join_pair(bm, fa, fb, e, false); + f_new = BM_faces_join_pair(bm, l_a, l_b, false); if (f_new) { /* maintain active face */ @@ -437,12 +437,12 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) { BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { - BMFace *fa, *fb; - if (BM_edge_face_pair(e, &fa, &fb)) { + BMLoop *l_a, *l_b; + if (BM_edge_loop_pair(e, &l_a, &l_b)) { BMFace *f_new; /* join faces */ - f_new = BM_faces_join_pair(bm, fa, fb, e, false); + f_new = BM_faces_join_pair(bm, l_a, l_b, false); /* maintain active face */ if (act_face && bm->act_face == NULL) { diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index c68130bc11d..f33a60ccc5c 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -136,7 +136,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) i++; } while ((v != f_verts[0])); - if (BM_face_exists(f_verts, i, NULL) == false) { + if (!BM_face_exists(f_verts, i)) { BMFace *f; /* don't use calc_edges option because we already have the edges */ diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 9c41e4f2115..81ec2860cf7 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -119,7 +119,8 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) }; BMFace *f, *example = NULL; - if (BM_face_exists(t->v, 3, &f)) { + f = BM_face_exists(t->v, 3); + if (f != NULL) { /* If the operator is run with "use_existing_faces" * disabled, but an output face in the hull is the * same as a face in the existing mesh, it should not diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index bc620e4a020..655fb346976 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -361,16 +361,16 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float); for (i = 0; i < totedge; i++) { - BMFace *f_a, *f_b; + BMLoop *l_a, *l_b; e = jedges[i].data; - f_a = e->l->f; - f_b = e->l->radial_next->f; + l_a = e->l; + l_b = e->l->radial_next; /* check if another edge already claimed this face */ - if ((f_a->len == 3) && (f_b->len == 3)) { + if ((l_a->f->len == 3) && (l_b->f->len == 3)) { BMFace *f_new; - f_new = BM_faces_join_pair(bm, f_a, f_b, e, true); + f_new = BM_faces_join_pair(bm, l_a, l_b, true); if (f_new) { BMO_face_flag_enable(bm, f_new, FACE_OUT); } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 6da591b23a0..0ad8247e539 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -160,7 +160,7 @@ finally: } if (STACK_SIZE(edges) >= 3) { - if (!BM_face_exists(verts, STACK_SIZE(edges), NULL)) { + if (!BM_face_exists(verts, STACK_SIZE(edges))) { BMFace *f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP); BLI_assert(f_new != f); diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c index 8938d086c1a..6bd3174d27a 100644 --- a/source/blender/bmesh/operators/bmo_triangulate.c +++ b/source/blender/bmesh/operators/bmo_triangulate.c @@ -253,10 +253,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) if (BMO_edge_flag_test(bm, e, ELE_NEW)) { /* in rare cases the edges face will have already been removed from the edge */ if (LIKELY(e->l)) { - BMFace *f_new = BM_faces_join_pair( - bm, e->l->f, - e->l->radial_next->f, e, - false); /* join faces */ + BMFace *f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false); if (f_new) { BMO_face_flag_enable(bm, f_new, ELE_NEW); BM_edge_kill(bm, e); diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c index 978cceee37c..e2c36299ddf 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c +++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c @@ -322,9 +322,7 @@ void BM_mesh_decimate_dissolve_ex( i = BM_elem_index_get(e); if (BM_edge_is_manifold(e)) { - f_new = BM_faces_join_pair(bm, e->l->f, - e->l->radial_next->f, e, - false); /* join faces */ + f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false); if (f_new) { BMLoop *l_first, *l_iter; diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index 0fc571bc0a8..92300ae66a2 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -74,7 +74,7 @@ static bool bm_vert_dissolve_fan_test(BMVert *v) ((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) || ((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1))) { - if (!BM_face_exists(varr, tot_edge, NULL)) { + if (!BM_face_exists(varr, tot_edge)) { return true; } } diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 6ff6de33d56..8f3bf88af65 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -317,11 +317,6 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su } } - if (mesh->getPositions().empty()) { - fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str()); - return false; - } - return true; } @@ -329,11 +324,15 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me) { // vertices COLLADAFW::MeshVertexData& pos = mesh->getPositions(); + if (pos.empty()) { + return; + } + int stride = pos.getStride(0); if (stride == 0) stride = 3; - - me->totvert = mesh->getPositions().getFloatValues()->getCount() / stride; - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); + + me->totvert = pos.getFloatValues()->getCount() / stride; + me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); MVert *mvert; int i; diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index b16e2e2b0d3..908111ebae6 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -113,11 +113,6 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B node.addMatrix("transform",d_obmat); break; } - case BC_TRANSFORMATION_TYPE_BOTH: - { - node.addMatrix("transform",d_obmat); - /* fall-through */ - } case BC_TRANSFORMATION_TYPE_TRANSROTLOC: { float loc[3], rot[3], scale[3]; diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index 0017c66836a..a4416608584 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -43,8 +43,7 @@ typedef enum BC_export_mesh_type { typedef enum BC_export_transformation_type { BC_TRANSFORMATION_TYPE_MATRIX, - BC_TRANSFORMATION_TYPE_TRANSROTLOC, - BC_TRANSFORMATION_TYPE_BOTH + BC_TRANSFORMATION_TYPE_TRANSROTLOC } BC_export_transformation_type; struct bContext; diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index e5c2b8ace4e..9a47c6b2438 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -383,7 +383,7 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED; - atomic_add_u(&this->m_chunksFinished, 1); + atomic_add_and_fetch_u(&this->m_chunksFinished, 1); if (memoryBuffers) { for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) { MemoryBuffer *buffer = memoryBuffers[index]; diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp index bba5c8702b8..6bfd8ae3888 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.cpp +++ b/source/blender/compositor/operations/COM_TextureOperation.cpp @@ -118,7 +118,7 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y * interpolaiton and (b) in such configuration multitex() sinply floor's the value * which often produces artifacts. */ - if ((m_texture->imaflag & TEX_INTERPOL) == 0) { + if (m_texture != NULL && (m_texture->imaflag & TEX_INTERPOL) == 0) { u += 0.5f / cx; v += 0.5f / cy; } diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index fd2a521bec5..ab12a8d5b3e 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -45,6 +45,7 @@ set(SRC intern/builder/deg_builder_nodes.cc intern/builder/deg_builder_pchanmap.cc intern/builder/deg_builder_relations.cc + intern/builder/deg_builder_relations_keys.cc intern/builder/deg_builder_transitive.cc intern/debug/deg_debug_graphviz.cc intern/eval/deg_eval.cc diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index 0945da439ef..fdc86540171 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -51,8 +51,12 @@ extern "C" { /* Graph Building -------------------------------- */ -/* Build depsgraph for the given scene, and dump results in given graph container */ -void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene); +/* Build depsgraph for the given scene, and dump results in given + * graph container. + */ +void DEG_graph_build_from_scene(struct Depsgraph *graph, + struct Main *bmain, + struct Scene *scene); /* Tag relations from the given graph for update. */ void DEG_graph_tag_relations_update(struct Depsgraph *graph); @@ -85,31 +89,69 @@ struct CacheFile; struct Object; typedef enum eDepsSceneComponentType { - DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */ - DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters? - DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */ + /* Parameters Component - Default when nothing else fits + * (i.e. just SDNA property setting). + */ + DEG_SCENE_COMP_PARAMETERS, + /* Animation Component + * TODO(sergey): merge in with parameters? + */ + DEG_SCENE_COMP_ANIMATION, + /* Sequencer Component (Scene Only). */ + DEG_SCENE_COMP_SEQUENCER, } eDepsSceneComponentType; typedef enum eDepsObjectComponentType { - DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */ - DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs? - DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters? - DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */ - DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */ - + /* Parameters Component - Default when nothing else fits + * (i.e. just SDNA property setting). + */ + DEG_OB_COMP_PARAMETERS, + /* Generic "Proxy-Inherit" Component. + * TODO(sergey): Also for instancing of subgraphs? + */ + DEG_OB_COMP_PROXY, + /* Animation Component. + * + * TODO(sergey): merge in with parameters? + */ + DEG_OB_COMP_ANIMATION, + /* Transform Component (Parenting/Constraints) */ + DEG_OB_COMP_TRANSFORM, + /* Geometry Component (DerivedMesh/Displist) */ + DEG_OB_COMP_GEOMETRY, + /* Evaluation-Related Outer Types (with Subdata) */ - DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */ - DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */ - - DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */ - DEG_OB_COMP_SHADING, /* Material Shading Component */ - DEG_OB_COMP_CACHE, /* Cache Component */ + + /* Pose Component - Owner/Container of Bones Eval */ + DEG_OB_COMP_EVAL_POSE, + /* Bone Component - Child/Subcomponent of Pose */ + DEG_OB_COMP_BONE, + + /* Particle Systems Component */ + DEG_OB_COMP_EVAL_PARTICLES, + /* Material Shading Component */ + DEG_OB_COMP_SHADING, + /* Cache Component */ + DEG_OB_COMP_CACHE, } eDepsObjectComponentType; -void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description); -void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description); -void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description); -void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, struct CacheFile *cache_file, eDepsObjectComponentType component, const char *description); +void DEG_add_scene_relation(struct DepsNodeHandle *node, + struct Scene *scene, + eDepsSceneComponentType component, + const char *description); +void DEG_add_object_relation(struct DepsNodeHandle *node, struct + Object *ob, + eDepsObjectComponentType component, + const char *description); +void DEG_add_bone_relation(struct DepsNodeHandle *handle, + struct Object *ob, + const char *bone_name, + eDepsObjectComponentType component, + const char *description); +void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, + struct CacheFile *cache_file, + eDepsObjectComponentType component, + const char *description); /* TODO(sergey): Remove once all geometry update is granular. */ void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag); @@ -117,8 +159,22 @@ void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short fla /* Utility functions for physics modifiers */ typedef bool (*DEG_CollobjFilterFunction)(struct Object *obj, struct ModifierData *md); -void DEG_add_collision_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name); -void DEG_add_forcefield_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name); +void DEG_add_collision_relations(struct DepsNodeHandle *handle, + struct Scene *scene, + Object *ob, + struct Group *group, + int layer, + unsigned int modifier_type, + DEG_CollobjFilterFunction fn, + bool dupli, + const char *name); +void DEG_add_forcefield_relations(struct DepsNodeHandle *handle, + struct Scene *scene, + Object *ob, + struct EffectorWeights *eff, + bool add_absorption, + int skip_forcefield, + const char *name); /* ************************************************ */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 6169100d574..8939e4cc93a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -34,6 +34,8 @@ #include <stack> #include "DNA_anim_types.h" +#include "DNA_object_types.h" +#include "DNA_ID.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -56,10 +58,46 @@ string deg_fcurve_id_name(const FCurve *fcu) return string(fcu->rna_path) + index_buf; } +static bool check_object_needs_evaluation(Object *object) +{ + if (object->recalc & OB_RECALC_ALL) { + /* Object is tagged for update anyway, no need to re-tag it. */ + return false; + } + if (object->type == OB_MESH) { + return object->derivedFinal == NULL; + } + else if (ELEM(object->type, + OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) + { + return object->curve_cache == NULL; + } + return false; +} + void deg_graph_build_finalize(Depsgraph *graph) { + /* STEP 1: Make sure new invisible dependencies are ready for use. + * + * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice + * to do it ahead of a time and don't spend time on flushing updates on + * every frame change. + */ + GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) + { + if (id_node->layers == 0 || 1) { + ID *id = id_node->id; + if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + if (check_object_needs_evaluation(object)) { + id_node->tag_update(graph); + } + } + } + } + GHASH_FOREACH_END(); + /* STEP 2: Flush visibility layers from children to parent. */ std::stack<OperationDepsNode *> stack; - foreach (OperationDepsNode *node, graph->operations) { IDDepsNode *id_node = node->owner->owner; node->done = 0; @@ -78,7 +116,6 @@ void deg_graph_build_finalize(Depsgraph *graph) node->owner->layers = id_node->layers; id_node->id->tag |= LIB_TAG_DOIT; } - while (!stack.empty()) { OperationDepsNode *node = stack.top(); stack.pop(); @@ -104,8 +141,9 @@ void deg_graph_build_finalize(Depsgraph *graph) } } } - - /* Re-tag IDs for update if it was tagged before the relations update tag. */ + /* STEP 3: Re-tag IDs for update if it was tagged before the relations + * update tag. + */ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) { GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components) @@ -121,6 +159,13 @@ void deg_graph_build_finalize(Depsgraph *graph) id_node->tag_update(graph); id->tag &= ~LIB_TAG_DOIT; } + else if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + if (object->recalc & OB_RECALC_ALL) { + id_node->tag_update(graph); + id->tag &= ~LIB_TAG_DOIT; + } + } id_node->finalize_build(); } GHASH_FOREACH_END(); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index 225cc64ae4d..9b37aaa12ff 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -56,12 +56,14 @@ struct StackEntry { void deg_graph_detect_cycles(Depsgraph *graph) { - /* Not is not visited at all during traversal. */ - const int NODE_NOT_VISITED = 0; - /* Node has been visited during traversal and not in current stack. */ - const int NODE_VISITED = 1; - /* Node has been visited during traversal and is in current stack. */ - const int NODE_IN_STACK = 2; + enum { + /* Not is not visited at all during traversal. */ + NODE_NOT_VISITED = 0, + /* Node has been visited during traversal and not in current stack. */ + NODE_VISITED = 1, + /* Node has been visited during traversal and is in current stack. */ + NODE_IN_STACK = 2, + }; std::stack<StackEntry> traversal_stack; foreach (OperationDepsNode *node, graph->operations) { @@ -77,21 +79,23 @@ void deg_graph_detect_cycles(Depsgraph *graph) entry.from = NULL; entry.via_relation = NULL; traversal_stack.push(entry); - node->done = NODE_IN_STACK; + node->tag = NODE_IN_STACK; } else { - node->done = NODE_NOT_VISITED; + node->tag = NODE_NOT_VISITED; } + node->done = 0; } while (!traversal_stack.empty()) { - StackEntry &entry = traversal_stack.top(); + StackEntry& entry = traversal_stack.top(); OperationDepsNode *node = entry.node; bool all_child_traversed = true; - foreach (DepsRelation *rel, node->outlinks) { + for (int i = node->done; i < node->outlinks.size(); ++i) { + DepsRelation *rel = node->outlinks[i]; if (rel->to->type == DEPSNODE_TYPE_OPERATION) { OperationDepsNode *to = (OperationDepsNode *)rel->to; - if (to->done == NODE_IN_STACK) { + if (to->tag == NODE_IN_STACK) { printf("Dependency cycle detected:\n"); printf(" '%s' depends on '%s' through '%s'\n", to->full_identifier().c_str(), @@ -107,23 +111,24 @@ void deg_graph_detect_cycles(Depsgraph *graph) current->via_relation->name); current = current->from; } - /* TODO(sergey): So called roussian rlette cycle solver. */ + /* TODO(sergey): So called russian roulette cycle solver. */ rel->flag |= DEPSREL_FLAG_CYCLIC; } - else if (to->done == NODE_NOT_VISITED) { + else if (to->tag == NODE_NOT_VISITED) { StackEntry new_entry; new_entry.node = to; new_entry.from = &entry; new_entry.via_relation = rel; traversal_stack.push(new_entry); - to->done = NODE_IN_STACK; + to->tag = NODE_IN_STACK; all_child_traversed = false; + node->done = i; break; } } } if (all_child_traversed) { - node->done = NODE_VISITED; + node->tag = NODE_VISITED; traversal_stack.pop(); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 1812384440f..12050e3e003 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -34,7 +34,6 @@ #include <stdio.h> #include <stdlib.h> -#include <string.h> #include "MEM_guardedalloc.h" @@ -109,6 +108,40 @@ extern "C" { namespace DEG { +namespace { + +struct BuilderWalkUserData { + DepsgraphNodeBuilder *builder; + Scene *scene; +}; + +static void modifier_walk(void *user_data, + struct Object * /*ob*/, + struct Object **obpoin, + int /*cd_flag*/) +{ + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + if (*obpoin) { + data->builder->build_object(data->scene, NULL, *obpoin); + } +} + +void constraint_walk(bConstraint * /*con*/, + ID **idpoin, + bool /*is_reference*/, + void *user_data) +{ + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + if (*idpoin) { + ID *id = *idpoin; + if (GS(id->name) == ID_OB) { + data->builder->build_object(data->scene, NULL, (Object *)id); + } + } +} + +} /* namespace */ + /* ************ */ /* Node Builder */ @@ -131,8 +164,7 @@ RootDepsNode *DepsgraphNodeBuilder::add_root_node() IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id) { - const char *idtype_name = BKE_idcode_to_name(GS(id->name)); - return m_graph->add_id_node(id, string(id->name + 2) + "[" + idtype_name + "]"); + return m_graph->add_id_node(id, id->name); } TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id) @@ -179,7 +211,7 @@ TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id) ComponentDepsNode *DepsgraphNodeBuilder::add_component_node( ID *id, eDepsNode_Type comp_type, - const string &comp_name) + const char *comp_name) { IDDepsNode *id_node = add_id_node(id); ComponentDepsNode *comp_node = id_node->add_component(comp_type, comp_name); @@ -192,15 +224,19 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &description) + const char *name, + int name_tag) { - OperationDepsNode *op_node = comp_node->has_operation(opcode, description); + OperationDepsNode *op_node = comp_node->has_operation(opcode, + name, + name_tag); if (op_node == NULL) { - op_node = comp_node->add_operation(optype, op, opcode, description); + op_node = comp_node->add_operation(optype, op, opcode, name, name_tag); m_graph->operations.push_back(op_node); } else { - fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n", + fprintf(stderr, + "add_operation: Operation already exists - %s has %s at %p\n", comp_node->identifier().c_str(), op_node->identifier().c_str(), op_node); @@ -212,14 +248,15 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( ID *id, eDepsNode_Type comp_type, - const string &comp_name, + const char *comp_name, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &description) + const char *name, + int name_tag) { ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name); - return add_operation_node(comp_node, optype, op, opcode, description); + return add_operation_node(comp_node, optype, op, opcode, name, name_tag); } OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( @@ -228,38 +265,54 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& description) + const char *name, + int name_tag) { - return add_operation_node(id, comp_type, "", optype, op, opcode, description); + return add_operation_node(id, + comp_type, + "", + optype, + op, + opcode, + name, + name_tag); } bool DepsgraphNodeBuilder::has_operation_node(ID *id, eDepsNode_Type comp_type, - const string &comp_name, + const char *comp_name, eDepsOperation_Code opcode, - const string &description) + const char *name, + int name_tag) { - return find_operation_node(id, comp_type, comp_name, opcode, description) != NULL; + return find_operation_node(id, + comp_type, + comp_name, + opcode, + name, + name_tag) != NULL; } OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( ID *id, eDepsNode_Type comp_type, - const string &comp_name, + const char *comp_name, eDepsOperation_Code opcode, - const string &description) + const char *name, + int name_tag) { ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name); - return comp_node->has_operation(opcode, description); + return comp_node->has_operation(opcode, name, name_tag); } OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( ID *id, eDepsNode_Type comp_type, eDepsOperation_Code opcode, - const string& description) + const char *name, + int name_tag) { - return find_operation_node(id, comp_type, "", opcode, description); + return find_operation_node(id, comp_type, "", opcode, name, name_tag); } /* **** Build functions for entity nodes **** */ @@ -386,19 +439,22 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group) { /*Object *ob = go->ob;*/ - /* Each "group object" is effectively a separate instance of the underlying - * object data. When the group is evaluated, the transform results and/or - * some other attributes end up getting overridden by the group + /* Each "group object" is effectively a separate instance of the + * underlying object data. When the group is evaluated, the transform + * results and/or some other attributes end up getting overridden by + * the group. */ } - /* create a node for representing subgraph */ + /* Create a node for representing subgraph. */ SubgraphDepsNode *subgraph_node = m_graph->add_subgraph_node(&group->id); subgraph_node->graph = subgraph; - /* make a copy of the data this node will need? */ - // XXX: do we do this now, or later? - // TODO: need API function which queries graph's ID's hash, and duplicates those blocks thoroughly with all outside links removed... + /* Make a copy of the data this node will need? */ + /* XXX: do we do this now, or later? */ + /* TODO: need API function which queries graph's ID's hash, and duplicates + * those blocks thoroughly with all outside links removed. + */ return subgraph_node; } @@ -407,18 +463,40 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) { if (ob->id.tag & LIB_TAG_DOIT) { IDDepsNode *id_node = m_graph->find_id_node(&ob->id); - id_node->layers |= base->lay; + if (base != NULL) { + id_node->layers |= base->lay; + } return; } + ob->id.tag |= LIB_TAG_DOIT; IDDepsNode *id_node = add_id_node(&ob->id); - id_node->layers |= base->lay; + if (base != NULL) { + id_node->layers |= base->lay; + } ob->customdata_mask = 0; - /* standard components */ + /* Standard components. */ build_object_transform(scene, ob); - /* object data */ + if (ob->parent != NULL) { + build_object(scene, NULL, ob->parent); + } + if (ob->modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.scene = scene; + modifiers_foreachObjectLink(ob, modifier_walk, &data); + } + if (ob->constraints.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.scene = scene; + modifiers_foreachObjectLink(ob, modifier_walk, &data); + BKE_constraints_id_loop(&ob->constraints, constraint_walk, &data); + } + + /* Object data. */ if (ob->data) { /* type-specific data... */ switch (ob->type) { @@ -428,15 +506,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) case OB_SURF: case OB_MBALL: case OB_LATTICE: - { - /* TODO(sergey): This way using this object's - * properties as driver target works fine. - * - * Does this depend on other nodes? - */ - add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL, - DEG_OPCODE_PLACEHOLDER, "Parameters Eval"); - build_obdata_geom(scene, ob); /* TODO(sergey): Only for until we support granular * update of curves. @@ -448,7 +517,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) } } break; - } case OB_ARMATURE: /* Pose */ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) { @@ -617,12 +685,17 @@ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu) OperationDepsNode *driver_op = find_operation_node(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, - deg_fcurve_id_name(fcu)); + fcu->rna_path, + fcu->array_index); if (driver_op == NULL) { - driver_op = add_operation_node(id, DEPSNODE_TYPE_PARAMETERS, - DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_driver, _1, id, fcu), - DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu)); + driver_op = add_operation_node(id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_EXEC, + function_bind(BKE_animsys_eval_driver, _1, id, fcu), + DEG_OPCODE_DRIVER, + fcu->rna_path, + fcu->array_index); } /* tag "scripted expression" drivers as needing Python (due to GIL issues, etc.) */ @@ -807,7 +880,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) /* Rebuild pose if not up to date. */ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild(ob, arm); + BKE_pose_rebuild_ex(ob, arm, false); /* XXX: Without this animation gets lost in certain circumstances * after loading file. Need to investigate further since it does * not happen with simple scenes.. @@ -972,6 +1045,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) { ID *obdata = (ID *)ob->data; + /* TODO(sergey): This way using this object's properties as driver target + * works fine. + * + * Does this depend on other nodes? + */ + add_operation_node(&ob->id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_POST, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Parameters Eval"); + /* Temporary uber-update node, which does everything. * It is for the being we're porting old dependencies into the new system. * We'll get rid of this node as soon as all the granular update functions @@ -979,35 +1064,45 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) * * TODO(sergey): Get rid of this node. */ - add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_POST, function_bind(BKE_object_eval_uber_data, _1, scene, ob), + add_operation_node(&ob->id, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_POST, + function_bind(BKE_object_eval_uber_data, _1, scene, ob), DEG_OPCODE_GEOMETRY_UBEREVAL); - add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, NULL, - DEG_OPCODE_PLACEHOLDER, "Eval Init"); + add_operation_node(&ob->id, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Eval Init"); // TODO: "Done" operation /* Modifiers */ if (ob->modifiers.first) { - ModifierData *md; - - for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) { - add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_modifier, _1, scene, ob, md), - DEG_OPCODE_GEOMETRY_MODIFIER, md->name); + for (ModifierData *md = (ModifierData *)ob->modifiers.first; + md != NULL; + md = md->next) + { + add_operation_node(&ob->id, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_EXEC, + function_bind(BKE_object_eval_modifier, + _1, + scene, + ob, + md), + DEG_OPCODE_GEOMETRY_MODIFIER, + md->name); } } /* materials */ if (ob->totcol) { - int a; - - for (a = 1; a <= ob->totcol; a++) { + for (int a = 1; a <= ob->totcol; a++) { Material *ma = give_current_material(ob, a); - - if (ma) { + if (ma != NULL) { // XXX?! ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY); build_material(geom_node, ma); @@ -1032,16 +1127,23 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) build_animdata(obdata); - /* nodes for result of obdata's evaluation, and geometry evaluation on object */ + /* Nodes for result of obdata's evaluation, and geometry + * evaluation on object. + */ switch (ob->type) { case OB_MESH: { //Mesh *me = (Mesh *)ob->data; /* evaluation operations */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_mesh_eval_geometry, + _1, + (Mesh *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); break; } @@ -1049,48 +1151,76 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) { Object *mom = BKE_mball_basis_find(scene, ob); - /* motherball - mom depends on children! */ + /* Motherball - mom depends on children! */ if (mom == ob) { /* metaball evaluation operations */ /* NOTE: only the motherball gets evaluated! */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_mball_eval_geometry, _1, (MetaBall *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_mball_eval_geometry, + _1, + (MetaBall *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); } break; } case OB_CURVE: + case OB_SURF: case OB_FONT: { - /* curve evaluation operations */ + /* Curve/nurms evaluation operations. */ /* - calculate curve geometry (including path) */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); - - /* - calculate curve path - this is used by constraints, etc. */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_EXEC, function_bind(BKE_curve_eval_path, _1, (Curve *)obdata), - DEG_OPCODE_GEOMETRY_PATH, "Path"); - break; - } + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_curve_eval_geometry, + _1, + (Curve *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); + + /* Calculate curve path - this is used by constraints, etc. */ + if (ELEM(ob->type, OB_CURVE, OB_FONT)) { + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_EXEC, + function_bind(BKE_curve_eval_path, + _1, + (Curve *)obdata), + DEG_OPCODE_GEOMETRY_PATH, + "Path"); + } - case OB_SURF: /* Nurbs Surface */ - { - /* nurbs evaluation operations */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + /* Make sure objects used for bevel.taper are in the graph. + * NOTE: This objects might be not linked to the scene. + */ + Curve *cu = (Curve *)obdata; + if (cu->bevobj != NULL) { + build_object(scene, NULL, cu->bevobj); + } + if (cu->taperobj != NULL) { + build_object(scene, NULL, cu->bevobj); + } + if (ob->type == OB_FONT && cu->textoncurve != NULL) { + build_object(scene, NULL, cu->textoncurve); + } break; } - case OB_LATTICE: /* Lattice */ + case OB_LATTICE: { - /* lattice evaluation operations */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + /* Lattice evaluation operations. */ + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_lattice_eval_geometry, + _1, + (Lattice *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); break; } } @@ -1171,15 +1301,20 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree /* nodetree's nodes... */ for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) { - if (bnode->id) { - if (GS(bnode->id->name) == ID_MA) { - build_material(owner_node, (Material *)bnode->id); + ID *id = bnode->id; + if (id != NULL) { + short id_type = GS(id->name); + if (id_type == ID_MA) { + build_material(owner_node, (Material *)id); } - else if (bnode->type == ID_TE) { - build_texture(owner_node, (Tex *)bnode->id); + else if (id_type == ID_TE) { + build_texture(owner_node, (Tex *)id); + } + else if (id_type == ID_IM) { + build_image((Image *)id); } else if (bnode->type == NODE_GROUP) { - bNodeTree *group_ntree = (bNodeTree *)bnode->id; + bNodeTree *group_ntree = (bNodeTree *)id; if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) { build_nodetree(owner_node, group_ntree); } @@ -1236,10 +1371,33 @@ void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex) return; } tex_id->tag |= LIB_TAG_DOIT; - /* texture itself */ + /* Texture itself. */ build_animdata(tex_id); - /* texture's nodetree */ + /* Texture's nodetree. */ build_nodetree(owner_node, tex->nodetree); + /* Special cases for different IDs which texture uses. */ + if (tex->type == TEX_IMAGE) { + if (tex->ima != NULL) { + build_image(tex->ima); + } + } +} + +void DepsgraphNodeBuilder::build_image(Image *image) { + ID *image_id = &image->id; + if (image_id->tag & LIB_TAG_DOIT) { + return; + } + image_id->tag |= LIB_TAG_DOIT; + /* Image ID node itself. */ + add_id_node(image_id); + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(image_id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_EXEC, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Image Eval"); } void DepsgraphNodeBuilder::build_compositor(Scene *scene) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index f378f076804..72dc73357bf 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -38,6 +38,7 @@ struct bGPdata; struct ListBase; struct GHash; struct ID; +struct Image; struct FCurve; struct Group; struct Key; @@ -75,43 +76,49 @@ struct DepsgraphNodeBuilder { ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, - const string& comp_name = ""); + const char *comp_name = ""); OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& description = ""); + const char *name = "", + int name_tag = -1); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, - const string& comp_name, + const char *comp_name, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& description = ""); + const char *name = "", + int name_tag = -1); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& description = ""); + const char *name = "", + int name_tag = -1); bool has_operation_node(ID *id, eDepsNode_Type comp_type, - const string& comp_name, + const char *comp_name, eDepsOperation_Code opcode, - const string& description = ""); + const char *name = "", + int name_tag = -1); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, - const string &comp_name, + const char *comp_name, eDepsOperation_Code opcode, - const string &description = ""); + const char *name = "", + int name_tag = -1); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Code opcode, - const string &description = ""); + const char *name = "", + int name_tag = -1); void build_scene(Main *bmain, Scene *scene); SubgraphDepsNode *build_subgraph(Group *group); @@ -142,6 +149,7 @@ struct DepsgraphNodeBuilder { void build_material(DepsNode *owner_node, Material *ma); void build_texture(DepsNode *owner_node, Tex *tex); void build_texture_stack(DepsNode *owner_node, MTex **texture_stack); + void build_image(Image *image); void build_world(World *world); void build_compositor(Scene *scene); void build_gpencil(bGPdata *gpd); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 09c7d9ab9de..fe75de5e350 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -34,13 +34,12 @@ #include <stdio.h> #include <stdlib.h> -#include <string.h> +#include <cstring> /* required for STREQ later on. */ #include "MEM_guardedalloc.h" extern "C" { #include "BLI_blenlib.h" -#include "BLI_string.h" #include "BLI_utildefines.h" #include "DNA_action_types.h" @@ -211,10 +210,12 @@ OperationDepsNode *DepsgraphRelationBuilder::find_node( return NULL; } - OperationDepsNode *op_node = comp_node->find_operation(key.opcode, key.name); + OperationDepsNode *op_node = comp_node->find_operation(key.opcode, + key.name, + key.name_tag); if (!op_node) { fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n", - DEG_OPNAMES[key.opcode], key.name.c_str()); + DEG_OPNAMES[key.opcode], key.name); } return op_node; } @@ -236,7 +237,7 @@ OperationDepsNode *DepsgraphRelationBuilder::has_node( if (!comp_node) { return NULL; } - return comp_node->has_operation(key.opcode, key.name); + return comp_node->has_operation(key.opcode, key.name, key.name_tag); } void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc, @@ -449,6 +450,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o if (ob->id.tag & LIB_TAG_DOIT) { return; } + ob->id.tag |= LIB_TAG_DOIT; /* Object Transforms */ eDepsOperation_Code base_op = (ob->parent) ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL; @@ -500,7 +502,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o build_animdata(&ob->id); // XXX: This should be hooked up by the build_animdata code - if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) { + if (needs_animdata_node(&ob->id)) { ComponentKey adt_key(&ob->id, DEPSNODE_TYPE_ANIMATION); add_relation(adt_key, local_transform_key, DEPSREL_TYPE_OPERATION, "Object Animation"); } @@ -837,11 +839,66 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) /* drivers */ for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) { - OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu)); + OperationKey driver_key(id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu->rna_path, + fcu->array_index); /* create the driver's relations to targets */ build_driver(id, fcu); + /* Special case for array drivers: we can not multithread them because + * of the way how they work internally: animation system will write the + * whole array back to RNA even when changing individual array value. + * + * Some tricky things here: + * - array_index is -1 for single channel drivers, meaning we only have + * to do some magic when array_index is not -1. + * - We do relation from next array index to a previous one, so we don't + * have to deal with array index 0. + * + * TODO(sergey): Avoid liner lookup somehow. + */ + if (fcu->array_index > 0) { + FCurve *fcu_prev = NULL; + for (FCurve *fcu_candidate = (FCurve *)adt->drivers.first; + fcu_candidate != NULL; + fcu_candidate = fcu_candidate->next) + { + /* Writing to different RNA paths is */ + if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) { + continue; + } + /* We only do relation from previous fcurve to previous one. */ + if (fcu_candidate->array_index >= fcu->array_index) { + continue; + } + /* Choose fcurve with highest possible array index. */ + if (fcu_prev == NULL || + fcu_candidate->array_index > fcu_prev->array_index) + { + fcu_prev = fcu_candidate; + } + } + if (fcu_prev != NULL) { + OperationKey prev_driver_key(id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu_prev->rna_path, + fcu_prev->array_index); + OperationKey driver_key(id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu->rna_path, + fcu->array_index); + add_relation(prev_driver_key, + driver_key, + DEPSREL_TYPE_OPERATION, + "[Driver Order]"); + } + } + /* prevent driver from occurring before own animation... */ if (adt->action || adt->nla_tracks.first) { add_relation(adt_key, driver_key, DEPSREL_TYPE_OPERATION, @@ -853,7 +910,11 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) { ChannelDriver *driver = fcu->driver; - OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu)); + OperationKey driver_key(id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu->rna_path, + fcu->array_index); bPoseChannel *pchan = NULL; /* create dependency between driver and data affected by it */ @@ -1356,10 +1417,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, if (data->poletar != NULL) { if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { // XXX: same armature issues - ready vs done? - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->subtarget); + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); } - else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { + else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) { /* vertex group target */ /* NOTE: for now, we don't need to represent vertex groups separately... */ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY); @@ -1527,7 +1588,7 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) "Armature Eval"); add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency"); - if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) { + if (needs_animdata_node(&ob->id)) { ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation"); } @@ -1765,7 +1826,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje * for either the modifier needing time, or that it is animated. */ /* XXX: Remove this hack when these links are added as part of build_animdata() instead */ - if (modifier_dependsOnTime(md) == false) { + if (modifier_dependsOnTime(md) == false && needs_animdata_node(&ob->id)) { ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); add_relation(animation_key, mod_key, DEPSREL_TYPE_OPERATION, "Modifier Animation"); } @@ -1848,15 +1909,18 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje // XXX: these needs geom data, but where is geom stored? if (cu->bevobj) { ComponentKey bevob_key(&cu->bevobj->id, DEPSNODE_TYPE_GEOMETRY); + build_object(bmain, scene, cu->bevobj); add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel"); } if (cu->taperobj) { ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY); + build_object(bmain, scene, cu->taperobj); add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper"); } if (ob->type == OB_FONT) { if (cu->textoncurve) { - ComponentKey textoncurve_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY); + ComponentKey textoncurve_key(&cu->textoncurve->id, DEPSNODE_TYPE_GEOMETRY); + build_object(bmain, scene, cu->textoncurve); add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve"); } } @@ -2063,7 +2127,7 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id) { AnimData *adt = BKE_animdata_from_id(id); if (adt != NULL) { - return adt->action != NULL; + return (adt->action != NULL) || (adt->nla_tracks.first != NULL); } return false; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 5240aa24b54..8d8ad6772b8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -81,108 +81,83 @@ struct ComponentDepsNode; struct OperationDepsNode; struct RootPChanMap; -struct RootKey -{ - RootKey() {} +struct RootKey { + RootKey(); }; struct TimeSourceKey { - TimeSourceKey() : id(NULL) {} - TimeSourceKey(ID *id) : id(id) {} + TimeSourceKey(); + TimeSourceKey(ID *id); - string identifier() const - { - return string("TimeSourceKey"); - } + string identifier() const; ID *id; }; struct ComponentKey { - ComponentKey() : - id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("") - {} - ComponentKey(ID *id, eDepsNode_Type type, const string &name = "") : - id(id), type(type), name(name) - {} - - string identifier() const - { - const char *idname = (id) ? id->name : "<None>"; + ComponentKey(); + ComponentKey(ID *id, eDepsNode_Type type, const char *name = ""); - char typebuf[5]; - BLI_snprintf(typebuf, sizeof(typebuf), "%d", type); - - return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')"; - } + string identifier() const; ID *id; eDepsNode_Type type; - string name; + const char *name; }; struct OperationKey { - OperationKey() : - id(NULL), component_type(DEPSNODE_TYPE_UNDEFINED), component_name(""), opcode(DEG_OPCODE_OPERATION), name("") - {} - - OperationKey(ID *id, eDepsNode_Type component_type, const string &name) : - id(id), component_type(component_type), component_name(""), opcode(DEG_OPCODE_OPERATION), name(name) - {} - OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, const string &name) : - id(id), component_type(component_type), component_name(component_name), opcode(DEG_OPCODE_OPERATION), name(name) - {} - - OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode) : - id(id), component_type(component_type), component_name(""), opcode(opcode), name("") - {} - OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode) : - id(id), component_type(component_type), component_name(component_name), opcode(opcode), name("") - {} - - OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, const string &name) : - id(id), component_type(component_type), component_name(""), opcode(opcode), name(name) - {} - OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode, const string &name) : - id(id), component_type(component_type), component_name(component_name), opcode(opcode), name(name) - {} - - string identifier() const - { - char typebuf[5]; - BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type); - - return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')"; - } - + OperationKey(); + OperationKey(ID *id, + eDepsNode_Type component_type, + const char *name, + int name_tag = -1); + OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + const char *name, + int name_tag); + + OperationKey(ID *id, + eDepsNode_Type component_type, + eDepsOperation_Code opcode); + OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + eDepsOperation_Code opcode); + + OperationKey(ID *id, + eDepsNode_Type component_type, + eDepsOperation_Code opcode, + const char *name, + int name_tag = -1); + OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + eDepsOperation_Code opcode, + const char *name, + int name_tag = -1); + + string identifier() const; ID *id; eDepsNode_Type component_type; - string component_name; + const char *component_name; eDepsOperation_Code opcode; - string name; + const char *name; + int name_tag; }; struct RNAPathKey { - // Note: see depsgraph_build.cpp for implementation + /* NOTE: see depsgraph_build.cpp for implementation */ RNAPathKey(ID *id, const char *path); - RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) : - id(id), ptr(ptr), prop(prop) - {} - - string identifier() const - { - const char *id_name = (id) ? id->name : "<No ID>"; - const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>"; - - return string("RnaPathKey(") + "id: " + id_name + ", prop: " + prop_name + "')"; - } + RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop); + string identifier() const; ID *id; PointerRNA ptr; @@ -270,7 +245,7 @@ protected: template <typename KeyType> DepsNodeHandle create_node_handle(const KeyType& key, - const string& default_name = ""); + const char *default_name = ""); bool needs_animdata_node(ID *id); @@ -280,7 +255,7 @@ private: struct DepsNodeHandle { - DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") : + DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const char *default_name = "") : builder(builder), node(node), default_name(default_name) @@ -290,7 +265,7 @@ struct DepsNodeHandle DepsgraphRelationBuilder *builder; OperationDepsNode *node; - const string &default_name; + const char *default_name; }; /* Utilities for Builders ----------------------------------------------------- */ @@ -318,6 +293,7 @@ void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, else { if (!op_from) { /* XXX TODO handle as error or report if needed */ + node_from = find_node(key_from); fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n", type, description, key_from.identifier().c_str()); } @@ -383,7 +359,7 @@ void DepsgraphRelationBuilder::add_node_handle_relation( template <typename KeyType> DepsNodeHandle DepsgraphRelationBuilder::create_node_handle( const KeyType &key, - const string &default_name) + const char *default_name) { return DepsNodeHandle(this, find_node(key), default_name); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc new file mode 100644 index 00000000000..7ada04e8f74 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -0,0 +1,211 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph + */ + +#include "intern/builder/deg_builder_relations.h" + +namespace DEG { + +///////////////////////////////////////// +// Root. + +RootKey::RootKey() +{ +} + +///////////////////////////////////////// +// Time source. + +TimeSourceKey::TimeSourceKey() + : id(NULL) +{ +} + +TimeSourceKey::TimeSourceKey(ID *id) + : id(id) +{ +} + +string TimeSourceKey::identifier() const +{ + return string("TimeSourceKey"); +} + +///////////////////////////////////////// +// Component. + +ComponentKey::ComponentKey() + : id(NULL), + type(DEPSNODE_TYPE_UNDEFINED), + name("") +{ +} + +ComponentKey::ComponentKey(ID *id, eDepsNode_Type type, const char *name) + : id(id), + type(type), + name(name) +{ +} + +string ComponentKey::identifier() const +{ + const char *idname = (id) ? id->name : "<None>"; + char typebuf[5]; + BLI_snprintf(typebuf, sizeof(typebuf), "%d", type); + return string("ComponentKey(") + + idname + ", " + typebuf + ", '" + name + "')"; +} + +///////////////////////////////////////// +// Operation. + +OperationKey::OperationKey() + : id(NULL), + component_type(DEPSNODE_TYPE_UNDEFINED), + component_name(""), + opcode(DEG_OPCODE_OPERATION), + name(""), + name_tag(-1) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(""), + opcode(DEG_OPCODE_OPERATION), + name(name), + name_tag(name_tag) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(DEG_OPCODE_OPERATION), + name(name), + name_tag(name_tag) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + eDepsOperation_Code opcode) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(""), + name_tag(-1) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + eDepsOperation_Code opcode) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(""), + name_tag(-1) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + eDepsOperation_Code opcode, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(name), + name_tag(name_tag) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + eDepsOperation_Code opcode, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(name), + name_tag(name_tag) +{ +} + +string OperationKey::identifier() const +{ + char typebuf[5]; + BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type); + return string("OperationKey(") + + "t: " + typebuf + + ", cn: '" + component_name + + "', c: " + DEG_OPNAMES[opcode] + + ", n: '" + name + "')"; +} + +///////////////////////////////////////// +// RNA path. + +RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) + : id(id), + ptr(ptr), + prop(prop) +{ +} + +string RNAPathKey::identifier() const +{ + const char *id_name = (id) ? id->name : "<No ID>"; + const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>"; + return string("RnaPathKey(") + "id: " + id_name + + ", prop: " + prop_name + "')"; +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc index 70cd5f11a47..0d56ce71c7d 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc @@ -321,7 +321,7 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx, static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx, const DepsNode *node) { - string name = node->identifier().c_str(); + string name = node->identifier(); if (node->type == DEPSNODE_TYPE_ID_REF) { IDDepsNode *id_node = (IDDepsNode *)node; char buf[256]; diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 2b7c63767ab..3502267d9ca 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -32,8 +32,6 @@ #include "intern/depsgraph.h" /* own include */ -#include <string.h> - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -53,6 +51,8 @@ extern "C" { #include "RNA_access.h" } +#include <cstring> + #include "DEG_depsgraph.h" #include "intern/nodes/deg_node.h" @@ -116,7 +116,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr, const PropertyRNA *prop, ID **id, eDepsNode_Type *type, - string *subdata) + const char **subdata) { if (!ptr->type) return false; @@ -232,7 +232,7 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr, { ID *id; eDepsNode_Type type; - string name; + const char *name; /* Get querying conditions. */ if (pointer_to_id_node_criteria(ptr, prop, &id)) { @@ -240,8 +240,9 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr, } else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) { IDDepsNode *id_node = find_id_node(id); - if (id_node) + if (id_node != NULL) { return id_node->find_component(type, name); + } } return NULL; @@ -328,7 +329,7 @@ IDDepsNode *Depsgraph::find_id_node(const ID *id) const return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id)); } -IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name) +IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name) { IDDepsNode *id_node = find_id_node(id); if (!id_node) { diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 08b264f8497..e668facd645 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -101,22 +101,6 @@ struct Depsgraph { ~Depsgraph(); /** - * Find node which matches the specified description. - * - * \param id: ID block that is associated with this - * \param subdata: identifier used for sub-ID data (e.g. bone) - * \param type: type of node we're dealing with - * \param name: custom identifier assigned to node - * - * \return A node matching the required characteristics if it exists - * or NULL if no such node exists in the graph. - */ - DepsNode *find_node(const ID *id, - eDepsNode_Type type, - const string &subdata, - const string &name); - - /** * Convenience wrapper to find node given just pointer + property. * * \param ptr: pointer to the data that node will represent @@ -136,7 +120,7 @@ struct Depsgraph { void clear_subgraph_nodes(); IDDepsNode *find_id_node(const ID *id) const; - IDDepsNode *add_id_node(ID *id, const string &name = ""); + IDDepsNode *add_id_node(ID *id, const char *name = ""); void remove_id_node(const ID *id); void clear_id_nodes(); diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 7a3b19e82c6..9952f714145 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -32,6 +32,8 @@ #include "MEM_guardedalloc.h" +// #define DEBUG_TIME + extern "C" { #include "DNA_cachefile_types.h" #include "DNA_object_types.h" @@ -41,6 +43,11 @@ extern "C" { #include "BLI_utildefines.h" #include "BLI_ghash.h" +#ifdef DEBUG_TIME +# include "PIL_time.h" +# include "PIL_time_utildefines.h" +#endif + #include "BKE_main.h" #include "BKE_collision.h" #include "BKE_effect.h" @@ -190,6 +197,10 @@ void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag) */ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene) { +#ifdef DEBUG_TIME + TIMEIT_START(DEG_graph_build_from_scene); +#endif + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); /* 1) Generate all the nodes in the graph first */ @@ -239,6 +250,10 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene) abort(); } #endif + +#ifdef DEBUG_TIME + TIMEIT_END(DEG_graph_build_from_scene); +#endif } /* Tag graph relations for update. */ @@ -309,7 +324,15 @@ void DEG_scene_graph_free(Scene *scene) } } -void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name) +void DEG_add_collision_relations(DepsNodeHandle *handle, + Scene *scene, + Object *ob, + Group *group, + int layer, + unsigned int modifier_type, + DEG_CollobjFilterFunction fn, + bool dupli, + const char *name) { unsigned int numcollobj; Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli); @@ -327,7 +350,13 @@ void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *o MEM_freeN(collobjs); } -void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name) +void DEG_add_forcefield_relations(DepsNodeHandle *handle, + Scene *scene, + Object *ob, + EffectorWeights *effector_weights, + bool add_absorption, + int skip_forcefield, + const char *name) { ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false); @@ -339,17 +368,33 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object * if (eff->psys) { DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_EVAL_PARTICLES, name); - /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */ + /* TODO: remove this when/if EVAL_PARTICLES is sufficient + * for up to date particles. + */ DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_GEOMETRY, name); } if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) { - DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain"); - DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_GEOMETRY, "Smoke Force Domain"); + DEG_add_object_relation(handle, + eff->pd->f_source, + DEG_OB_COMP_TRANSFORM, + "Smoke Force Domain"); + DEG_add_object_relation(handle, + eff->pd->f_source, + DEG_OB_COMP_GEOMETRY, + "Smoke Force Domain"); } if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) { - DEG_add_collision_relations(handle, scene, ob, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption"); + DEG_add_collision_relations(handle, + scene, + ob, + NULL, + eff->ob->lay, + eModifierType_Collision, + NULL, + true, + "Force Absorption"); } } } diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h index e5d3d1f5861..2d8e7dc841c 100644 --- a/source/blender/depsgraph/intern/depsgraph_intern.h +++ b/source/blender/depsgraph/intern/depsgraph_intern.h @@ -63,8 +63,8 @@ struct DepsNodeFactory { virtual const char *tname() const = 0; virtual DepsNode *create_node(const ID *id, - const string &subdata, - const string &name) const = 0; + const char *subdata, + const char *name) const = 0; }; template <class NodeType> @@ -73,7 +73,7 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory { eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; } const char *tname() const { return NodeType::typeinfo.tname; } - DepsNode *create_node(const ID *id, const string &subdata, const string &name) const + DepsNode *create_node(const ID *id, const char *subdata, const char *name) const { DepsNode *node = OBJECT_GUARDED_NEW(NodeType); @@ -81,12 +81,14 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory { node->type = type(); node->tclass = tclass(); - if (!name.empty()) + if (name[0] != '\0') { /* set name if provided ... */ node->name = name; - else + } + else { /* ... otherwise use default type name */ node->name = tname(); + } node->init(id, subdata); diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 4f27dab258d..e8ed03666a6 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -31,7 +31,7 @@ */ #include <stdio.h> -#include <cstring> +#include <cstring> /* required for memset */ #include <queue> extern "C" { diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index c3fd202d832..e926f83bcbe 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -152,7 +152,7 @@ static void deg_task_run_func(TaskPool *pool, } if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) { BLI_assert(child->num_links_pending > 0); - atomic_sub_uint32(&child->num_links_pending, 1); + atomic_sub_and_fetch_uint32(&child->num_links_pending, 1); } if (child->num_links_pending == 0) { bool is_scheduled = atomic_fetch_and_or_uint8( @@ -287,7 +287,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers, { if (dec_parents) { BLI_assert(node->num_links_pending > 0); - atomic_sub_uint32(&node->num_links_pending, 1); + atomic_sub_and_fetch_uint32(&node->num_links_pending, 1); } if (node->num_links_pending == 0) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc index 67d64aae8bf..060544a4407 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc @@ -30,10 +30,10 @@ * Implementation of tools for debugging the depsgraph */ -#include <cstring> - #include "intern/eval/deg_eval_debug.h" +#include <cstring> /* required for STREQ later on. */ + extern "C" { #include "BLI_listbase.h" #include "BLI_ghash.h" @@ -53,10 +53,10 @@ namespace DEG { DepsgraphStats *DepsgraphDebug::stats = NULL; -static string get_component_name(eDepsNode_Type type, const string &name = "") +static string get_component_name(eDepsNode_Type type, const char *name = "") { DepsNodeFactory *factory = deg_get_node_factory(type); - if (name.empty()) { + if (name[0] != '\0') { return string(factory->tname()); } else { @@ -116,7 +116,7 @@ void DepsgraphDebug::task_started(Depsgraph *graph, */ DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, - comp->name), + comp->name).c_str(), true); times_clear(comp_stats->times); } @@ -146,7 +146,7 @@ void DepsgraphDebug::task_completed(Depsgraph *graph, DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, - comp->name), + comp->name).c_str(), true); times_add(comp_stats->times, time); } @@ -226,7 +226,7 @@ DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create) DepsgraphStatsComponent *DepsgraphDebug::get_component_stats( DepsgraphStatsID *id_stats, - const string &name, + const char *name, bool create) { DepsgraphStatsComponent *comp_stats; @@ -234,13 +234,14 @@ DepsgraphStatsComponent *DepsgraphDebug::get_component_stats( comp_stats != NULL; comp_stats = comp_stats->next) { - if (STREQ(comp_stats->name, name.c_str())) + if (STREQ(comp_stats->name, name)) { break; + } } if (!comp_stats && create) { comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats"); - BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name)); + BLI_strncpy(comp_stats->name, name, sizeof(comp_stats->name)); BLI_addtail(&id_stats->components, comp_stats); } return comp_stats; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.h b/source/blender/depsgraph/intern/eval/deg_eval_debug.h index 9109019eb2d..0bbe88cc9ca 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_debug.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.h @@ -66,10 +66,10 @@ struct DepsgraphDebug { static DepsgraphStatsID *get_id_stats(ID *id, bool create); static DepsgraphStatsComponent *get_component_stats(DepsgraphStatsID *id_stats, - const string &name, + const char *name, bool create); static DepsgraphStatsComponent *get_component_stats(ID *id, - const string &name, + const char *name, bool create) { return get_component_stats(get_id_stats(id, create), name, create); diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index eb408f293de..57b25c10670 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -31,7 +31,7 @@ #include "intern/nodes/deg_node.h" #include <stdio.h> -#include <string.h> +#include <cstring> /* required for STREQ later on. */ #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -72,7 +72,7 @@ DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname) DepsNode::DepsNode() { - name[0] = '\0'; + name = ""; } DepsNode::~DepsNode() @@ -122,7 +122,7 @@ RootDepsNode::~RootDepsNode() OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode); } -TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name) +TimeSourceDepsNode *RootDepsNode::add_time_source(const char *name) { if (!time_source) { DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE); @@ -142,12 +142,24 @@ static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE; /* ID Node ================================================ */ +IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type, + const char *name) + : type(type), name(name) +{ +} + +bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const +{ + return type == other.type && + STREQ(name, other.name); +} + static unsigned int id_deps_node_hash_key(const void *key_v) { const IDDepsNode::ComponentIDKey *key = reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v); return hash_combine(BLI_ghashutil_uinthash(key->type), - BLI_ghashutil_strhash_p(key->name.c_str())); + BLI_ghashutil_strhash_p(key->name)); } static bool id_deps_node_hash_key_cmp(const void *a, const void *b) @@ -173,7 +185,7 @@ static void id_deps_node_hash_value_free(void *value_v) } /* Initialize 'id' node - from pointer data given. */ -void IDDepsNode::init(const ID *id, const string &UNUSED(subdata)) +void IDDepsNode::init(const ID *id, const char *UNUSED(subdata)) { /* Store ID-pointer. */ BLI_assert(id != NULL); @@ -204,14 +216,14 @@ IDDepsNode::~IDDepsNode() } ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type, - const string &name) const + const char *name) const { ComponentIDKey key(type, name); return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key)); } ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, - const string &name) + const char *name) { ComponentDepsNode *comp_node = find_component(type, name); if (!comp_node) { @@ -226,7 +238,7 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, return comp_node; } -void IDDepsNode::remove_component(eDepsNode_Type type, const string &name) +void IDDepsNode::remove_component(eDepsNode_Type type, const char *name) { ComponentDepsNode *comp_node = find_component(type, name); if (comp_node) { @@ -281,7 +293,7 @@ static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF; /* Subgraph Node ========================================== */ /* Initialize 'subgraph' node - from pointer data given. */ -void SubgraphDepsNode::init(const ID *id, const string &UNUSED(subdata)) +void SubgraphDepsNode::init(const ID *id, const char *UNUSED(subdata)) { /* Store ID-ref if provided. */ this->root_id = (ID *)id; diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index b2262c4bd12..7c2f53840b6 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -32,6 +32,8 @@ #include "intern/depsgraph_types.h" +#include "BLI_utildefines.h" + struct ID; struct GHash; struct Scene; @@ -57,7 +59,7 @@ struct DepsNode { }; /* Identifier - mainly for debugging purposes. */ - string name; + const char *name; /* Structural type of node. */ eDepsNode_Type type; @@ -78,8 +80,9 @@ struct DepsNode { /* Nodes which depend on this one. */ Relations outlinks; - /* Generic tag for traversal algorithms */ + /* Generic tags for traversal algorithms. */ int done; + int tag; /* Methods. */ @@ -90,7 +93,7 @@ struct DepsNode { string full_identifier() const; virtual void init(const ID * /*id*/, - const string &/*subdata*/) {} + const char * /*subdata*/) {} virtual void tag_update(Depsgraph * /*graph*/) {} @@ -129,7 +132,7 @@ struct RootDepsNode : public DepsNode { RootDepsNode(); ~RootDepsNode(); - TimeSourceDepsNode *add_time_source(const string &name = ""); + TimeSourceDepsNode *add_time_source(const char *name = ""); /* scene that this corresponds to */ Scene *scene; @@ -143,26 +146,21 @@ struct RootDepsNode : public DepsNode { /* ID-Block Reference */ struct IDDepsNode : public DepsNode { struct ComponentIDKey { - ComponentIDKey(eDepsNode_Type type, const string &name = "") - : type(type), name(name) {} - - bool operator== (const ComponentIDKey &other) const - { - return type == other.type && name == other.name; - } + ComponentIDKey(eDepsNode_Type type, const char *name = ""); + bool operator==(const ComponentIDKey &other) const; eDepsNode_Type type; - string name; + const char *name; }; - void init(const ID *id, const string &subdata); + void init(const ID *id, const char *subdata); ~IDDepsNode(); ComponentDepsNode *find_component(eDepsNode_Type type, - const string &name = "") const; + const char *name = "") const; ComponentDepsNode *add_component(eDepsNode_Type type, - const string &name = ""); - void remove_component(eDepsNode_Type type, const string &name = ""); + const char *name = ""); + void remove_component(eDepsNode_Type type, const char *name = ""); void clear_components(); void tag_update(Depsgraph *graph); @@ -189,7 +187,7 @@ struct IDDepsNode : public DepsNode { /* Subgraph Reference. */ struct SubgraphDepsNode : public DepsNode { - void init(const ID *id, const string &subdata); + void init(const ID *id, const char *subdata); ~SubgraphDepsNode(); /* Instanced graph. */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 01f33b6368b..06f91ac7fdc 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -31,7 +31,7 @@ #include "intern/nodes/deg_node_component.h" #include <stdio.h> -#include <string.h> +#include <cstring> /* required for STREQ later on. */ extern "C" { #include "BLI_utildefines.h" @@ -53,12 +53,50 @@ namespace DEG { /* Standard Component Methods ============================= */ +ComponentDepsNode::OperationIDKey::OperationIDKey() + : opcode(DEG_OPCODE_OPERATION), + name(""), + name_tag(-1) +{ +} + +ComponentDepsNode::OperationIDKey::OperationIDKey(eDepsOperation_Code opcode) + : opcode(opcode), + name(""), + name_tag(-1) +{ +} + +ComponentDepsNode::OperationIDKey::OperationIDKey(eDepsOperation_Code opcode, + const char *name, + int name_tag) + : opcode(opcode), + name(name), + name_tag(name_tag) +{ +} + +string ComponentDepsNode::OperationIDKey::identifier() const +{ + char codebuf[5]; + BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode); + return string("OperationIDKey(") + codebuf + ", " + name + ")"; +} + +bool ComponentDepsNode::OperationIDKey::operator==( + const OperationIDKey &other) const +{ + return (opcode == other.opcode) && + (STREQ(name, other.name)) && + (name_tag == other.name_tag); +} + static unsigned int comp_node_hash_key(const void *key_v) { const ComponentDepsNode::OperationIDKey *key = reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(key_v); return hash_combine(BLI_ghashutil_uinthash(key->opcode), - BLI_ghashutil_strhash_p(key->name.c_str())); + BLI_ghashutil_strhash_p(key->name)); } static bool comp_node_hash_key_cmp(const void *a, const void *b) @@ -95,7 +133,7 @@ ComponentDepsNode::ComponentDepsNode() : /* Initialize 'component' node - from pointer data given */ void ComponentDepsNode::init(const ID * /*id*/, - const string & /*subdata*/) + const char * /*subdata*/) { /* hook up eval context? */ // XXX: maybe this needs a special API? @@ -114,7 +152,7 @@ ComponentDepsNode::~ComponentDepsNode() string ComponentDepsNode::identifier() const { - string &idname = this->owner->name; + string idname = this->owner->name; char typebuf[16]; sprintf(typebuf, "(%d)", type); @@ -139,9 +177,11 @@ OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const } } -OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, const string &name) const +OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, + const char *name, + int name_tag) const { - OperationIDKey key(opcode, name); + OperationIDKey key(opcode, name, name_tag); return find_operation(key); } @@ -151,21 +191,26 @@ OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const } OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode, - const string &name) const + const char *name, + int name_tag) const { - OperationIDKey key(opcode, name); + OperationIDKey key(opcode, name, name_tag); return has_operation(key); } -OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name) +OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, + DepsEvalOperationCb op, + eDepsOperation_Code opcode, + const char *name, + int name_tag) { - OperationDepsNode *op_node = has_operation(opcode, name); + OperationDepsNode *op_node = has_operation(opcode, name, name_tag); if (!op_node) { DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION); op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name); /* register opnode in this component's operation set */ - OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name); + OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag); BLI_ghash_insert(operations_map, key, op_node); /* set as entry/exit node of component (if appropriate) */ @@ -197,16 +242,6 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, return op_node; } -void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name) -{ - /* unregister */ - OperationIDKey key(opcode, name); - BLI_ghash_remove(operations_map, - &key, - comp_node_hash_key_free, - comp_node_hash_key_free); -} - void ComponentDepsNode::clear_operations() { if (operations_map != NULL) { @@ -337,7 +372,7 @@ static DepsNodeFactoryImpl<PoseComponentDepsNode> DNTI_EVAL_POSE; /* Bone Component ========================================= */ /* Initialize 'bone component' node - from pointer data given */ -void BoneComponentDepsNode::init(const ID *id, const string &subdata) +void BoneComponentDepsNode::init(const ID *id, const char *subdata) { /* generic component-node... */ ComponentDepsNode::init(id, subdata); @@ -350,7 +385,7 @@ void BoneComponentDepsNode::init(const ID *id, const string &subdata) /* bone-specific node data */ Object *ob = (Object *)id; - this->pchan = BKE_pose_channel_find_name(ob->pose, subdata.c_str()); + this->pchan = BKE_pose_channel_find_name(ob->pose, subdata); } DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component"); diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index 7dec8eaaa90..969771a29c9 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -53,50 +53,38 @@ struct ComponentDepsNode : public DepsNode { struct OperationIDKey { eDepsOperation_Code opcode; - string name; - - - OperationIDKey() : - opcode(DEG_OPCODE_OPERATION), name("") - {} - OperationIDKey(eDepsOperation_Code opcode) : - opcode(opcode), name("") - {} - OperationIDKey(eDepsOperation_Code opcode, const string &name) : - opcode(opcode), name(name) - {} - - string identifier() const - { - char codebuf[5]; - BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode); - - return string("OperationIDKey(") + codebuf + ", " + name + ")"; - } - - bool operator==(const OperationIDKey &other) const - { - return (opcode == other.opcode) && (name == other.name); - } + const char *name; + int name_tag; + + OperationIDKey(); + OperationIDKey(eDepsOperation_Code opcode); + OperationIDKey(eDepsOperation_Code opcode, + const char *name, + int name_tag); + + string identifier() const; + bool operator==(const OperationIDKey &other) const; }; /* Typedef for container of operations */ ComponentDepsNode(); ~ComponentDepsNode(); - void init(const ID *id, const string &subdata); + void init(const ID *id, const char *subdata); string identifier() const; /* Find an existing operation, will throw an assert() if it does not exist. */ OperationDepsNode *find_operation(OperationIDKey key) const; OperationDepsNode *find_operation(eDepsOperation_Code opcode, - const string &name) const; + const char *name, + int name_tag) const; /* Check operation exists and return it. */ OperationDepsNode *has_operation(OperationIDKey key) const; OperationDepsNode *has_operation(eDepsOperation_Code opcode, - const string &name) const; + const char *name, + int name_tag) const; /** * Create a new node for representing an operation and add this to graph @@ -114,9 +102,9 @@ struct ComponentDepsNode : public DepsNode { OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &name); + const char *name, + int name_tag); - void remove_operation(eDepsOperation_Code opcode, const string &name); void clear_operations(); void tag_update(Depsgraph *graph); @@ -194,7 +182,7 @@ struct PoseComponentDepsNode : public ComponentDepsNode { /* Bone Component */ struct BoneComponentDepsNode : public ComponentDepsNode { - void init(const ID *id, const string &subdata); + void init(const ID *id, const char *subdata); struct bPoseChannel *pchan; /* the bone that this component represents */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc index 5847af29ac2..9eed4dfe8d8 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc @@ -68,7 +68,7 @@ string OperationDepsNode::full_identifier() const { string owner_str = ""; if (owner->type == DEPSNODE_TYPE_BONE) { - owner_str = owner->owner->name + "." + owner->name; + owner_str = string(owner->owner->name) + "." + owner->name; } else { owner_str = owner->owner->name; diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 262ce0b9e23..c0d6963acbb 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -57,6 +57,7 @@ #include "ED_anim_api.h" #include "ED_screen.h" #include "ED_sequencer.h" +#include "ED_util.h" #include "anim_intern.h" @@ -263,7 +264,8 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) ot->poll = change_frame_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* rna */ ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index ece0f18e96e..47e73f9b777 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -1328,6 +1328,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; ED_armature_sync_selection(arm->edbo); + BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 5015829f868..322476dcca0 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -626,7 +626,7 @@ void POSE_OT_flip_names(wmOperatorType *ot) /* api callbacks */ ot->exec = pose_flip_names_exec; - ot->poll = ED_operator_posemode; + ot->poll = ED_operator_posemode_local; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index cd0ea23e2d3..8e8345d34c9 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -685,6 +685,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) switch (event->type) { case LEFTMOUSE: /* confirm */ case RETKEY: + case PADENTER: { /* return to normal cursor and header status */ ED_area_headerprint(pso->sa, NULL); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 7dcbe2cc24c..ae83e899649 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -84,7 +84,8 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + ToolSettings *ts = CTX_data_tool_settings(C); + if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); return OPERATOR_CANCELLED; @@ -95,6 +96,15 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) id_us_min(&gpd->id); *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); + + /* if not exist brushes, create a new set */ + if (ts) { + if (BLI_listbase_is_empty(&ts->gp_brushes)) { + /* create new brushes */ + BKE_gpencil_brush_init_presets(ts); + } + } + } /* notifiers */ @@ -174,7 +184,8 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot) static int gp_layer_add_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + ToolSettings *ts = CTX_data_tool_settings(C); + /* if there's no existing Grease-Pencil data there, add some */ if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); @@ -183,6 +194,14 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op) if (*gpd_ptr == NULL) *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); + /* if not exist brushes, create a new set */ + if (ts) { + if (BLI_listbase_is_empty(&ts->gp_brushes)) { + /* create new brushes */ + BKE_gpencil_brush_init_presets(ts); + } + } + /* add new layer now */ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 6a558d1c185..ec09add56b8 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -183,6 +183,7 @@ int ED_operator_uvmap(struct bContext *C); int ED_operator_posemode_exclusive(struct bContext *C); int ED_operator_posemode_context(struct bContext *C); int ED_operator_posemode(struct bContext *C); +int ED_operator_posemode_local(struct bContext *C); int ED_operator_mask(struct bContext *C); diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index f5968397f65..a4afa958450 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -52,6 +52,8 @@ void ED_OT_flush_edits(struct wmOperatorType *ot); /* undo.c */ void ED_undo_push(struct bContext *C, const char *str); void ED_undo_push_op(struct bContext *C, struct wmOperator *op); +void ED_undo_grouped_push(struct bContext *C, const char *str); +void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op); void ED_undo_pop_op(struct bContext *C, struct wmOperator *op); void ED_undo_pop(struct bContext *C); void ED_undo_redo(struct bContext *C); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 31598a44b09..d7f06b7db13 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -1083,6 +1083,15 @@ static int depthdropper_poll(bContext *C) return 1; } } + else { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d && rv3d->persp == RV3D_CAMOB) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->camera && v3d->camera->data && !ID_IS_LINKED_DATABLOCK(v3d->camera->data)) { + return 1; + } + } + } return 0; } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 863f5e3852c..f3eeadb6604 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2219,7 +2219,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB /* ******************* copy and paste ******************** */ /* c = copy, v = paste */ -static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode) +static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, const char mode, const bool copy_array) { int buf_paste_len = 0; const char *buf_paste = ""; @@ -2255,6 +2255,46 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, if (but->poin == NULL && but->rnapoin.data == NULL) { /* pass */ } + else if (copy_array && but->rnapoin.data && but->rnaprop && + ELEM(RNA_property_subtype(but->rnaprop), PROP_COLOR, PROP_TRANSLATION, PROP_DIRECTION, + PROP_VELOCITY, PROP_ACCELERATION, PROP_MATRIX, PROP_EULER, PROP_QUATERNION, PROP_AXISANGLE, + PROP_XYZ, PROP_XYZ_LENGTH, PROP_COLOR_GAMMA, PROP_COORDS)) + { + float values[4]; + int array_length = RNA_property_array_length(&but->rnapoin, but->rnaprop); + + if (mode == 'c') { + char buf_copy[UI_MAX_DRAW_STR]; + + if (array_length == 4) { + values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3); + } + else { + values[3] = 0.0f; + } + ui_but_v3_get(but, values); + + BLI_snprintf(buf_copy, sizeof(buf_copy), "[%f, %f, %f, %f]", values[0], values[1], values[2], values[3]); + WM_clipboard_text_set(buf_copy, 0); + } + else { + if (sscanf(buf_paste, "[%f, %f, %f, %f]", &values[0], &values[1], &values[2], &values[3]) >= array_length) { + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); + + ui_but_v3_set(but, values); + if (but->rnaprop && array_length == 4) { + RNA_property_float_set_index(&but->rnapoin, but->rnaprop, 3, values[3]); + } + data->value = values[but->rnaindex]; + + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + else { + WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'"); + show_report = true; + } + } + } else if (mode == 'c') { /* Get many decimal places, then strip trailing zeros. * note: too high values start to give strange results */ @@ -6617,15 +6657,22 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) { bScreen *sc = CTX_wm_screen(C); + const bool has_panel_category = UI_panel_category_is_visible(ar); + const bool any_item_visible = has_panel_category; PointerRNA ptr; uiPopupMenu *pup; uiLayout *layout; + if (!any_item_visible) { + return; + } + RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr); pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE); layout = UI_popup_menu_layout(pup); - if (UI_panel_category_is_visible(ar)) { + + if (has_panel_category) { char tmpstr[80]; BLI_snprintf(tmpstr, sizeof(tmpstr), "%s" UI_SEP_CHAR_S "%s", IFACE_("Pin"), IFACE_("Shift+Left Mouse")); uiItemR(layout, &ptr, "use_pin", 0, tmpstr, ICON_NONE); @@ -6636,7 +6683,6 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) uiBut *but = block->buttons.last; but->flag |= UI_BUT_HAS_SEP_CHAR; } - } UI_popup_menu_end(C, pup); } @@ -6959,7 +7005,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) { /* handle copy-paste */ if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS && - IS_EVENT_MOD(event, ctrl, oskey) && !event->shift && !event->alt) + IS_EVENT_MOD(event, ctrl, oskey) && !event->shift) { /* Specific handling for listrows, we try to find their overlapping tex button. */ if (but->type == UI_BTYPE_LISTROW) { @@ -6969,7 +7015,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * data = but->active; } } - ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v'); + ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v', event->alt); return WM_UI_HANDLER_BREAK; } /* handle drop */ diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index ff9d2840e9c..65b12fcd64e 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -213,173 +213,6 @@ static void viconutil_set_point(GLint pt[2], int x, int y) pt[1] = y; } -static void viconutil_draw_tri(GLint(*pts)[2]) -{ - glBegin(GL_TRIANGLES); - glVertex2iv(pts[0]); - glVertex2iv(pts[1]); - glVertex2iv(pts[2]); - glEnd(); -} - -static void viconutil_draw_lineloop(GLint(*pts)[2], int numPoints) -{ - int i; - - glBegin(GL_LINE_LOOP); - for (i = 0; i < numPoints; i++) { - glVertex2iv(pts[i]); - } - glEnd(); -} - -static void viconutil_draw_lineloop_smooth(GLint(*pts)[2], int numPoints) -{ - glEnable(GL_LINE_SMOOTH); - viconutil_draw_lineloop(pts, numPoints); - glDisable(GL_LINE_SMOOTH); -} - -static void viconutil_draw_points(GLint(*pts)[2], int numPoints, int pointSize) -{ - int i; - - glBegin(GL_QUADS); - for (i = 0; i < numPoints; i++) { - int x = pts[i][0], y = pts[i][1]; - - glVertex2i(x - pointSize, y - pointSize); - glVertex2i(x + pointSize, y - pointSize); - glVertex2i(x + pointSize, y + pointSize); - glVertex2i(x - pointSize, y + pointSize); - } - glEnd(); -} - -/* Drawing functions */ - -static void vicon_x_draw(int x, int y, int w, int h, float alpha) -{ - x += 3; - y += 3; - w -= 6; - h -= 6; - - glEnable(GL_LINE_SMOOTH); - - glLineWidth(2.5); - - glColor4f(0.0, 0.0, 0.0, alpha); - glBegin(GL_LINES); - glVertex2i(x, y); - glVertex2i(x + w, y + h); - glVertex2i(x + w, y); - glVertex2i(x, y + h); - glEnd(); - - glDisable(GL_LINE_SMOOTH); -} - -static void vicon_view3d_draw(int x, int y, int w, int h, float alpha) -{ - int cx = x + w / 2; - int cy = y + h / 2; - int d = MAX2(2, h / 3); - - glColor4f(0.5, 0.5, 0.5, alpha); - glBegin(GL_LINES); - glVertex2i(x, cy - d); - glVertex2i(x + w, cy - d); - glVertex2i(x, cy + d); - glVertex2i(x + w, cy + d); - - glVertex2i(cx - d, y); - glVertex2i(cx - d, y + h); - glVertex2i(cx + d, y); - glVertex2i(cx + d, y + h); - glEnd(); - - glColor4f(0.0, 0.0, 0.0, alpha); - glBegin(GL_LINES); - glVertex2i(x, cy); - glVertex2i(x + w, cy); - glVertex2i(cx, y); - glVertex2i(cx, y + h); - glEnd(); -} - -static void vicon_edit_draw(int x, int y, int w, int h, float alpha) -{ - GLint pts[4][2]; - - viconutil_set_point(pts[0], x + 3, y + 3); - viconutil_set_point(pts[1], x + w - 3, y + 3); - viconutil_set_point(pts[2], x + w - 3, y + h - 3); - viconutil_set_point(pts[3], x + 3, y + h - 3); - - glColor4f(0.0, 0.0, 0.0, alpha); - viconutil_draw_lineloop(pts, 4); - - glColor3f(1, 1, 0.0); - viconutil_draw_points(pts, 4, 1); -} - -static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha) -{ - GLint pts[3][2]; - - viconutil_set_point(pts[0], x + w / 2, y + h - 2); - viconutil_set_point(pts[1], x + 3, y + 4); - viconutil_set_point(pts[2], x + w - 3, y + 4); - - glColor4f(0.5, 0.5, 0.5, alpha); - viconutil_draw_tri(pts); - - glColor4f(0.0, 0.0, 0.0, 1); - viconutil_draw_lineloop_smooth(pts, 3); - - glColor3f(1, 1, 0.0); - viconutil_draw_points(pts, 3, 1); -} - -static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float UNUSED(alpha)) -{ - GLint pts[3][2]; - - viconutil_set_point(pts[0], x + w / 2, y + h - 2); - viconutil_set_point(pts[1], x + 3, y + 4); - viconutil_set_point(pts[2], x + w - 3, y + 4); - - glColor4f(0.0f, 0.0f, 0.0f, 1); - viconutil_draw_lineloop_smooth(pts, 3); - - glColor3f(0.9f, 0.9f, 0.9f); - viconutil_draw_points(pts, 3, 1); -} - -static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha) -{ - GLint pts[3][2]; - int cx = x + w / 2; - int cy = y + w / 2; - int d = w / 3, d2 = w / 5; - - viconutil_set_point(pts[0], cx - d2, cy + d); - viconutil_set_point(pts[1], cx - d2, cy - d); - viconutil_set_point(pts[2], cx + d2, cy); - - glBegin(GL_TRIANGLES); - glColor4f(0.8f, 0.8f, 0.8f, alpha); - glVertex2iv(pts[0]); - glVertex2iv(pts[1]); - glColor4f(0.3f, 0.3f, 0.3f, alpha); - glVertex2iv(pts[2]); - glEnd(); - - glColor4f(0.0f, 0.0f, 0.0f, 1); - viconutil_draw_lineloop_smooth(pts, 3); -} - static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha) { GLint pts[3][2]; @@ -400,63 +233,6 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float glEnd(); } -static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha) -{ - GLint pts[3][2]; - int cx = x + w / 2; - int cy = y + w / 2; - int d = w / 3, d2 = w / 5; - - viconutil_set_point(pts[0], cx + d, cy + d2); - viconutil_set_point(pts[1], cx - d, cy + d2); - viconutil_set_point(pts[2], cx, cy - d2); - - glBegin(GL_TRIANGLES); - glColor4f(0.8f, 0.8f, 0.8f, alpha); - glVertex2iv(pts[0]); - glVertex2iv(pts[1]); - glColor4f(0.3f, 0.3f, 0.3f, alpha); - glVertex2iv(pts[2]); - glEnd(); - - glColor4f(0.0f, 0.0f, 0.0f, 1); - viconutil_draw_lineloop_smooth(pts, 3); -} - -static void vicon_move_up_draw(int x, int y, int w, int h, float UNUSED(alpha)) -{ - int d = -2; - - glEnable(GL_LINE_SMOOTH); - glLineWidth(1); - glColor3f(0.0, 0.0, 0.0); - - glBegin(GL_LINE_STRIP); - glVertex2i(x + w / 2 - d * 2, y + h / 2 + d); - glVertex2i(x + w / 2, y + h / 2 - d + 1); - glVertex2i(x + w / 2 + d * 2, y + h / 2 + d); - glEnd(); - - glDisable(GL_LINE_SMOOTH); -} - -static void vicon_move_down_draw(int x, int y, int w, int h, float UNUSED(alpha)) -{ - int d = 2; - - glEnable(GL_LINE_SMOOTH); - glLineWidth(1); - glColor3f(0.0, 0.0, 0.0); - - glBegin(GL_LINE_STRIP); - glVertex2i(x + w / 2 - d * 2, y + h / 2 + d); - glVertex2i(x + w / 2, y + h / 2 - d - 1); - glVertex2i(x + w / 2 + d * 2, y + h / 2 + d); - glEnd(); - - glDisable(GL_LINE_SMOOTH); -} - static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type) { /* init dummy theme state for Action Editor - where these colors are defined @@ -782,15 +558,6 @@ static void init_internal_icons(void) } } - def_internal_vicon(VICO_VIEW3D_VEC, vicon_view3d_draw); - def_internal_vicon(VICO_EDIT_VEC, vicon_edit_draw); - def_internal_vicon(VICO_EDITMODE_VEC_DEHLT, vicon_editmode_dehlt_draw); - def_internal_vicon(VICO_EDITMODE_VEC_HLT, vicon_editmode_hlt_draw); - def_internal_vicon(VICO_DISCLOSURE_TRI_RIGHT_VEC, vicon_disclosure_tri_right_draw); - def_internal_vicon(VICO_DISCLOSURE_TRI_DOWN_VEC, vicon_disclosure_tri_down_draw); - def_internal_vicon(VICO_MOVE_UP_VEC, vicon_move_up_draw); - def_internal_vicon(VICO_MOVE_DOWN_VEC, vicon_move_down_draw); - def_internal_vicon(VICO_X_VEC, vicon_x_draw); def_internal_vicon(VICO_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw); def_internal_vicon(VICO_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 5e24dc96255..539284030c2 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -2750,17 +2750,21 @@ void init_userdef_do_versions(void) } } + if (!USER_VERSION_ATLEAST(278, 3)) { + for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) { + /* Keyframe Indicators (were using wrong alpha) */ + btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255; + btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255; + } + } + /** * Include next version bump. * * (keep this block even if it becomes empty). */ { - for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) { - /* Keyframe Indicators (were using wrong alpha) */ - btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255; - btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255; - } + } if (U.pixelsize == 0.0f) diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 8659100df87..baae92f962e 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -305,7 +305,6 @@ void WM_OT_collada_export(wmOperatorType *ot) static EnumPropertyItem prop_bc_export_transformation_type[] = { {BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations"}, {BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations"}, - {BC_TRANSFORMATION_TYPE_BOTH, "both", 0, "Both", "Use <matrix> AND <translate>, <rotate>, <scale> to specify transformations"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index e31e4096ded..e05ce727e22 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -496,7 +496,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u } /* face should never exist */ - BLI_assert(BM_face_exists(f_verts, f_verts[3] ? 4 : 3, &f) == false); + BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3)); f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 7e31deba2c7..c57b0215d46 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1561,6 +1561,18 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op) /* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical state */ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true); BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + + const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out"); + const int tot_failed = tot - tot_rotate; + if (tot_failed != 0) { + /* If some edges fail to rotate, we need to re-select them, + * otherwise we can end up with invalid selection + * (unselected edge between 2 selected faces). */ + BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); + + BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed); + } + EDBM_selectmode_flush(em); if (!EDBM_op_finish(em, &bmop, op, true)) { diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 4fc61e0912e..438c3acdb11 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1139,7 +1139,6 @@ BMEdge *EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e) BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f) { - BMFace *f_mirr = NULL; BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len); BMLoop *l_iter, *l_first; @@ -1152,8 +1151,7 @@ BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f) } } while ((l_iter = l_iter->next) != l_first); - BM_face_exists(v_mirr_arr, f->len, &f_mirr); - return f_mirr; + return BM_face_exists(v_mirr_arr, f->len); } void EDBM_verts_mirror_cache_clear(BMEditMesh *em, BMVert *v) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 9f91feee4c6..8e64cdc9751 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1307,7 +1307,9 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (use_hierarchy || use_base_parent) { dupli_gh = BLI_ghash_ptr_new(__func__); - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + if (use_hierarchy) { + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + } } for (dob = lb->first; dob; dob = dob->next) { @@ -1344,10 +1346,17 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, copy_m4_m4(ob->obmat, dob->mat); BKE_object_apply_mat4(ob, ob->obmat, false, false); - if (dupli_gh) + if (dupli_gh) { BLI_ghash_insert(dupli_gh, dob, ob); - if (parent_gh) - BLI_ghash_insert(parent_gh, dob, ob); + } + if (parent_gh) { + void **val; + /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as 'the same', + * this avoids trying to insert same key several time and raise asserts in debug builds... */ + if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) { + *val = ob; + } + } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index d1232fd2aab..f448e925dd9 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1740,10 +1740,16 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in clear_sca_new_poins(); /* sensor/contr/act */ - /* newid may still have some trash from Outliner tree building, - * so clear that first to avoid errors [#26002] */ - for (ob = bmain->object.first; ob; ob = ob->id.next) - ob->id.newid = NULL; + /* newid may still have some trash from Outliner tree building, so clear that first to avoid errors, see T26002. + * We have to clear whole datablocks, not only Object one may be accessed here, see T49905. */ + ListBase *lbarray[MAX_LIBARRAY]; + int a = set_listbasepointers(bmain, lbarray); + while (a--) { + ListBase *lb = lbarray[a]; + for (ID *id = lb->first; id; id = id->next) { + id->newid = NULL; + } + } /* duplicate (must set newid) */ for (base = FIRSTBASE; base; base = base->next) { @@ -2235,7 +2241,7 @@ static int make_local_exec(bContext *C, wmOperator *op) "Orphan library objects added to the current scene to avoid loss"); } - BKE_library_make_local(bmain, NULL, false, false); /* NULL is all libs */ + BKE_library_make_local(bmain, NULL, NULL, false, false); /* NULL is all libs */ WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index bd016b7fcfb..56f59dca9a1 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -886,7 +886,7 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum) const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); /* warning, this lookup is _not_ fast */ - if (cd_dvert_offset != -1) { + if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) { BMVert *eve; BM_mesh_elem_table_ensure(em->bm, BM_VERT); eve = BM_vert_at_index(em->bm, vertnum); @@ -2604,6 +2604,8 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "all")) BKE_object_defgroup_remove_all(ob); + else if (RNA_boolean_get(op->ptr, "all_unlocked")) + BKE_object_defgroup_remove_all_ex(ob, true); else vgroup_delete_active(ob); @@ -2633,6 +2635,7 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups"); + RNA_def_boolean(ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups"); } static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 9d9ccf2f3ba..16842efb436 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -315,6 +315,12 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); IMB_freeImBuf(out); } + else if (gpd){ + /* If there are no strips, Grease Pencil still needs a buffer to draw on */ + ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect); + RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); + IMB_freeImBuf(out); + } if (gpd) { int i; @@ -479,23 +485,24 @@ static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, Rende /* copy image data from rectf */ // XXX: Needs conversion. unsigned char *src = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32; - float *dest = rp->rect; - - int x, y, rectx, recty; - rectx = rr->rectx; - recty = rr->recty; - for (y = 0; y < recty; y++) { - for (x = 0; x < rectx; x++) { - unsigned char *pixSrc = src + 4 * (rectx * y + x); - if (pixSrc[3] > 0) { - float *pixDest = dest + 4 * (rectx * y + x); - float float_src[4]; - srgb_to_linearrgb_uchar4(float_src, pixSrc); - addAlphaOverFloat(pixDest, float_src); + if (src != NULL) { + float *dest = rp->rect; + + int x, y, rectx, recty; + rectx = rr->rectx; + recty = rr->recty; + for (y = 0; y < recty; y++) { + for (x = 0; x < rectx; x++) { + unsigned char *pixSrc = src + 4 * (rectx * y + x); + if (pixSrc[3] > 0) { + float *pixDest = dest + 4 * (rectx * y + x); + float float_src[4]; + srgb_to_linearrgb_uchar4(float_src, pixSrc); + addAlphaOverFloat(pixDest, float_src); + } } } } - /* back layer status */ i = 0; for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 860a865466a..c69e01422e0 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -442,6 +442,17 @@ int ED_operator_posemode(bContext *C) return 0; } +int ED_operator_posemode_local(bContext *C) +{ + if (ED_operator_posemode(C)) { + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + bArmature *arm = ob->data; + return !(ID_IS_LINKED_DATABLOCK(&ob->id) || + ID_IS_LINKED_DATABLOCK(&arm->id)); + } + return false; +} + /* wrapper for ED_space_image_show_uvedit */ int ED_operator_uvedit(bContext *C) { @@ -2136,7 +2147,8 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot) ot->exec = frame_offset_exec; ot->poll = ED_operator_screenactive_norender; - ot->flag = 0; + ot->flag = OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* rna */ RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); @@ -2189,7 +2201,8 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot) ot->exec = frame_jump_exec; ot->poll = ED_operator_screenactive_norender; - ot->flag = OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* rna */ RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range"); @@ -2295,7 +2308,8 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot) ot->exec = keyframe_jump_exec; ot->poll = ED_operator_screenactive_norender; - ot->flag = OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* properties */ RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", ""); @@ -2357,7 +2371,8 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot) ot->exec = marker_jump_exec; ot->poll = ED_operator_screenactive_norender; - ot->flag = OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* properties */ RNA_def_boolean(ot->srna, "next", true, "Next Marker", ""); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index fe0fb3f5035..53434b18d06 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4688,7 +4688,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st sculpt_restore_mesh(sd, ob); if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) { - BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f); + BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail); } else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) { BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f); @@ -5406,7 +5406,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) if (!ts->sculpt->detail_percent) ts->sculpt->detail_percent = 25; if (ts->sculpt->constant_detail == 0.0f) - ts->sculpt->constant_detail = 30.0f; + ts->sculpt->constant_detail = 3.0f; /* Set sane default tiling offsets */ if (!ts->sculpt->paint.tile_offset[0]) ts->sculpt->paint.tile_offset[0] = 1.0f; @@ -5543,7 +5543,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) size = max_fff(bb_max[0], bb_max[1], bb_max[2]); /* update topology size */ - BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f); + BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail); sculpt_undo_push_begin("Dynamic topology flood fill"); sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS); @@ -5608,7 +5608,8 @@ static void sample_detail(bContext *C, int ss_co[2]) ray_start, ray_normal, false); if (srd.hit) { - sd->constant_detail = srd.detail * 100.0f; + /* convert edge length to detail resolution */ + sd->constant_detail = 1.0f / srd.detail; } } diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 58c538c4ee5..72de7e5c81c 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -587,6 +587,8 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS last_category = user->category; } + + UI_block_flag_enable(block, UI_BLOCK_NO_FLIP); } void uiTemplateTextureUser(uiLayout *layout, bContext *C) diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 6af36ea6778..83469a48165 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2510,7 +2510,7 @@ static void filelist_readjob_do( * Using an atomic operation to avoid having to lock thread... * Note that we do not really need this here currently, since there is a single listing thread, but better * remain consistent about threading! */ - *((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1); + *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1); /* Only thing we change in direntry here, so we need to free it first. */ MEM_freeN(entry->relpath); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index ea40d4eb5e1..dd282c427f6 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -7915,10 +7915,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (!render_override && sds->draw_velocity) { draw_smoke_velocity(sds, viewnormal); } - -#ifdef SMOKE_DEBUG_HEAT - draw_smoke_heat(smd->domain, ob); -#endif } } diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index b0e21601b9c..27ecbf83db5 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -1,4 +1,4 @@ -/* +/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -41,6 +41,7 @@ #include "BLI_math.h" #include "BKE_DerivedMesh.h" +#include "BKE_texture.h" #include "BKE_particle.h" #include "smoke_API.h" @@ -62,28 +63,33 @@ struct GPUTexture; # include "PIL_time_utildefines.h" #endif -static GPUTexture *create_flame_spectrum_texture(void) +/* *************************** Transfer functions *************************** */ + +enum { + TFUNC_FLAME_SPECTRUM = 0, + TFUNC_COLOR_RAMP = 1, +}; + +#define TFUNC_WIDTH 256 + +static void create_flame_spectrum_texture(float *data) { -#define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 - GPUTexture *tex; - int i, j, k; - float *spec_data = MEM_mallocN(SPEC_WIDTH * 4 * sizeof(float), "spec_data"); - float *spec_pixels = MEM_mallocN(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); + float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); - blackbody_temperature_to_rgb_table(spec_data, SPEC_WIDTH, 1500, 3000); + blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000); - for (i = 0; i < 16; i++) { - for (j = 0; j < 16; j++) { - for (k = 0; k < SPEC_WIDTH; k++) { - int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + for (int k = 0; k < TFUNC_WIDTH; k++) { + int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { - spec_pixels[index] = (spec_data[k * 4]); - spec_pixels[index + 1] = (spec_data[k * 4 + 1]); - spec_pixels[index + 2] = (spec_data[k * 4 + 2]); + spec_pixels[index] = (data[k * 4]); + spec_pixels[index + 1] = (data[k * 4 + 1]); + spec_pixels[index + 2] = (data[k * 4 + 2]); spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } @@ -94,19 +100,69 @@ static GPUTexture *create_flame_spectrum_texture(void) } } - tex = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); + memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH); - MEM_freeN(spec_data); MEM_freeN(spec_pixels); -#undef SPEC_WIDTH #undef FIRE_THRESH #undef MAX_FIRE_ALPHA #undef FULL_ON_FIRE +} + +static void create_color_ramp(const ColorBand *coba, float *data) +{ + for (int i = 0; i < TFUNC_WIDTH; i++) { + do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + } +} + +static GPUTexture *create_transfer_function(int type, const ColorBand *coba) +{ + float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__); + + switch (type) { + case TFUNC_FLAME_SPECTRUM: + create_flame_spectrum_texture(data); + break; + case TFUNC_COLOR_RAMP: + create_color_ramp(coba, data); + break; + } + + GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, data, NULL); + + MEM_freeN(data); return tex; } +static GPUTexture *create_field_texture(SmokeDomainSettings *sds) +{ + float *field = NULL; + + switch (sds->coba_field) { +#ifdef WITH_SMOKE + case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break; + case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break; + case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break; + case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break; + case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break; + case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break; + case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break; + case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break; + case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break; + case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break; + case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break; + case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break; + case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break; + case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break; +#endif + default: return NULL; + } + + return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field); +} + typedef struct VolumeSlicer { float size[3]; float min[3]; @@ -347,6 +403,7 @@ static int create_view_aligned_slices(VolumeSlicer *slicer, } static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec, + GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire, const float min[3], const float ob_sizei[3], const float invsize[3]) { @@ -359,6 +416,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture int densityscale_location; int spec_location, flame_location; int shadow_location, actcol_location; + int tfunc_location = 0; + int coba_location = 0; if (use_fire) { spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); @@ -370,6 +429,11 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture soot_location = GPU_shader_get_uniform(shader, "soot_texture"); stepsize_location = GPU_shader_get_uniform(shader, "step_size"); densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); + + if (sds->use_coba) { + tfunc_location = GPU_shader_get_uniform(shader, "transfer_texture"); + coba_location = GPU_shader_get_uniform(shader, "color_band_texture"); + } } GPU_shader_bind(shader); @@ -397,6 +461,14 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) mul_v3_v3(active_color, sds->active_color); GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); + + if (sds->use_coba) { + GPU_texture_bind(tex_tfunc, 4); + GPU_shader_uniform_texture(shader, tfunc_location, tex_tfunc); + + GPU_texture_bind(tex_coba, 5); + GPU_shader_uniform_texture(shader, coba_location, tex_coba); + } } GPU_shader_uniform_vector(shader, min_location, 3, 1, min); @@ -404,7 +476,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); } -static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire) +static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, + GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire) { GPU_shader_unbind(); @@ -417,20 +490,30 @@ static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool u } else { GPU_texture_unbind(sds->tex_shadow); + + if (sds->use_coba) { + GPU_texture_unbind(tex_tfunc); + GPU_texture_free(tex_tfunc); + + GPU_texture_unbind(tex_coba); + GPU_texture_free(tex_coba); + } } } static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer, const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire) { - GPUTexture *tex_spec = (do_fire) ? create_flame_spectrum_texture() : NULL; + GPUTexture *tex_spec = (do_fire) ? create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL) : NULL; + GPUTexture *tex_tfunc = (sds->use_coba) ? create_transfer_function(TFUNC_COLOR_RAMP, sds->coba) : NULL; + GPUTexture *tex_coba = (sds->use_coba) ? create_field_texture(sds) : NULL; GLuint vertex_buffer; glGenBuffers(1, &vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW); - bind_shader(sds, shader, tex_spec, do_fire, slicer->min, ob_sizei, invsize); + bind_shader(sds, shader, tex_spec, tex_tfunc, tex_coba, do_fire, slicer->min, ob_sizei, invsize); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, NULL); @@ -439,7 +522,7 @@ static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const Volum glDisableClientState(GL_VERTEX_ARRAY); - unbind_shader(sds, tex_spec, do_fire); + unbind_shader(sds, tex_spec, tex_tfunc, tex_coba, do_fire); /* cleanup */ @@ -459,7 +542,16 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame; - GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE); + GPUBuiltinShader builtin_shader; + + if (sds->use_coba) { + builtin_shader = GPU_SHADER_SMOKE_COBA; + } + else { + builtin_shader = GPU_SHADER_SMOKE; + } + + GPUShader *shader = GPU_shader_get_builtin_shader(builtin_shader); if (!shader) { fprintf(stderr, "Unable to create GLSL smoke shader.\n"); @@ -549,7 +641,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false); /* Draw fire separately (T47639). */ - if (use_fire) { + if (use_fire && !sds->use_coba) { glBlendFunc(GL_ONE, GL_ONE); draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true); } @@ -759,50 +851,3 @@ void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3]) UNUSED_VARS(domain, viewnormal); #endif } - -#ifdef SMOKE_DEBUG_HEAT -void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob) -{ - float x, y, z; - float x0, y0, z0; - int *base_res = domain->base_res; - int *res = domain->res; - int *res_min = domain->res_min; - int *res_max = domain->res_max; - float *heat = smoke_get_heat(domain->fluid); - - float min[3]; - float *cell_size = domain->cell_size; - float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f; - float vf = domain->scale / 16.f * 2.f; /* velocity factor */ - - /* set first position so that it doesn't jump when domain moves */ - x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size); - y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size); - z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size); - if (x0 < res_min[0]) x0 += step_size; - if (y0 < res_min[1]) y0 += step_size; - if (z0 < res_min[2]) z0 += step_size; - add_v3_v3v3(min, domain->p0, domain->obj_shift_f); - - for (x = floor(x0); x < res_max[0]; x += step_size) - for (y = floor(y0); y < res_max[1]; y += step_size) - for (z = floor(z0); z < res_max[2]; z += step_size) { - int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1]; - - float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]}; - - /* draw heat as different sized points */ - if (heat[index] >= 0.01f) { - float col_gb = 1.0f - heat[index]; - CLAMP(col_gb, 0.0f, 1.0f); - glColor3f(1.0f, col_gb, col_gb); - glPointSize(24.0f * heat[index]); - - glBegin(GL_POINTS); - glVertex3f(pos[0], pos[1], pos[2]); - glEnd(); - } - } -} -#endif diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 0e2cb95dd89..b11f42bcfef 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -296,14 +296,8 @@ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, const float min[3], const float max[3], const float viewnormal[3]); -//#define SMOKE_DEBUG_HEAT - void draw_smoke_velocity(struct SmokeDomainSettings *domain, float viewnormal[3]); -#ifdef SMOKE_DEBUG_HEAT -void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob); -#endif - /* workaround for trivial but noticeable camera bug caused by imprecision * between view border calculation in 2D/3D space, workaround for bug [#28037]. * without this define we get the old behavior which is to try and align them diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ef6cff19181..daf0aed59e7 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -3392,7 +3392,9 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) } protectedTransBits(td->protectflag, vec); - add_v3_v3v3(td->loc, td->iloc, vec); + if (td->loc) { + add_v3_v3v3(td->loc, td->iloc, vec); + } constraintTransLim(t, td); } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 9c266890d6d..ce3d903b8f6 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5583,7 +5583,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, if (tmode == TFM_TRANSLATION) { do_loc = true; } - else if (tmode == TFM_ROTATION) { + else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) { if (v3d->around == V3D_AROUND_ACTIVE) { if (ob != OBACT) do_loc = true; @@ -5728,7 +5728,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o else do_loc = true; } - else if (tmode == TFM_ROTATION) { + else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) { if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE)) do_loc = true; diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index ee6700666c0..4a9311416b3 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -217,6 +217,19 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) return OPERATOR_FINISHED; } +void ED_undo_grouped_push(bContext *C, const char *str) +{ + /* do nothing if previous undo task is the same as this one (or from the same undo group) */ + const char *last_undo = BKE_undo_get_name_last(); + + if (last_undo && STREQ(str, last_undo)) { + return; + } + + /* push as usual */ + ED_undo_push(C, str); +} + void ED_undo_pop(bContext *C) { ed_undo_step(C, 1, NULL); @@ -232,6 +245,16 @@ void ED_undo_push_op(bContext *C, wmOperator *op) ED_undo_push(C, op->type->name); } +void ED_undo_grouped_push_op(bContext *C, wmOperator *op) +{ + if (op->type->undo_group[0] != '\0') { + ED_undo_grouped_push(C, op->type->undo_group); + } + else { + ED_undo_grouped_push(C, op->type->name); + } +} + void ED_undo_pop_op(bContext *C, wmOperator *op) { /* search back a couple of undo's, in case something else added pushes */ diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 762329ee077..5b94db6e120 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -89,6 +89,7 @@ typedef enum GPUBuiltinShader { GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, GPU_SHADER_SMOKE = 2, GPU_SHADER_SMOKE_FIRE = 3, + GPU_SHADER_SMOKE_COBA = 4, } GPUBuiltinShader; GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 5cfb323bc4b..14f2764b009 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -68,6 +68,7 @@ static struct GPUShadersGlobal { GPUShader *sep_gaussian_blur; GPUShader *smoke; GPUShader *smoke_fire; + GPUShader *smoke_coba; /* cache for shader fx. Those can exist in combinations so store them here */ GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; } shaders; @@ -623,6 +624,13 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) NULL, NULL, NULL, 0, 0, 0); retval = GG.shaders.smoke_fire; break; + case GPU_SHADER_SMOKE_COBA: + if (!GG.shaders.smoke_coba) + GG.shaders.smoke_coba = GPU_shader_create( + datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, + NULL, NULL, "#define USE_COBA;\n", 0, 0, 0); + retval = GG.shaders.smoke_coba; + break; } if (retval == NULL) @@ -734,6 +742,11 @@ void GPU_shader_free_builtin_shaders(void) GG.shaders.smoke_fire = NULL; } + if (GG.shaders.smoke_coba) { + GPU_shader_free(GG.shaders.smoke_coba); + GG.shaders.smoke_coba = NULL; + } + for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) { if (GG.shaders.fx_shaders[i]) { GPU_shader_free(GG.shaders.fx_shaders[i]); diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 67da8201f66..4416b6494f9 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2822,7 +2822,7 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c } #ifdef BIT_OPERATIONS -vec2 calc_brick_texture(vec3 p, float mortar_size, float bias, +vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bias, float brick_width, float row_height, float offset_amount, int offset_frequency, float squash_amount, int squash_frequency) @@ -2843,17 +2843,26 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float bias, x = (p.x + offset) - brick_width * bricknum; y = p.y - row_height * rownum; - return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0), - (x < mortar_size || y < mortar_size || - x > (brick_width - mortar_size) || - y > (row_height - mortar_size)) ? 1.0 : 0.0); + float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0); + + float min_dist = min(min(x, y), min(brick_width - x, row_height - y)); + if(min_dist >= mortar_size) { + return vec2(tint, 0.0); + } + else if(mortar_smooth == 0.0) { + return vec2(tint, 1.0); + } + else { + min_dist = 1.0 - min_dist/mortar_size; + return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist)); + } } #endif void node_tex_brick(vec3 co, vec4 color1, vec4 color2, vec4 mortar, float scale, - float mortar_size, float bias, + float mortar_size, float mortar_smooth, float bias, float brick_width, float row_height, float offset_amount, float offset_frequency, float squash_amount, float squash_frequency, @@ -2861,7 +2870,7 @@ void node_tex_brick(vec3 co, { #ifdef BIT_OPERATIONS vec2 f2 = calc_brick_texture(co * scale, - mortar_size, bias, + mortar_size, mortar_smooth, bias, brick_width, row_height, offset_amount, int(offset_frequency), squash_amount, int(squash_frequency)); @@ -2871,7 +2880,7 @@ void node_tex_brick(vec3 co, float facm = 1.0 - tint; color1 = facm * color1 + tint * color2; } - color = (f == 1.0) ? mortar : color1; + color = mix(color1, mortar, f); fac = f; #else color = vec4(1.0); diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl index fd790009e02..6ded453225e 100644 --- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl @@ -8,10 +8,17 @@ uniform float density_scale; uniform sampler3D soot_texture; uniform sampler3D shadow_texture; +#ifdef USE_COBA +uniform sampler1D transfer_texture; +uniform sampler3D color_band_texture; +#endif + void main() { /* compute color and density from volume texture */ vec4 soot = texture3D(soot_texture, coords); + +#ifndef USE_COBA vec3 soot_color; if (soot.a != 0) { soot_color = active_color * soot.rgb / soot.a; @@ -31,6 +38,11 @@ void main() /* premultiply alpha */ vec4 color = vec4(soot_alpha * soot_color, soot_alpha); +#else + float color_band = texture3D(color_band_texture, coords).r; + vec4 transfer_function = texture1D(transfer_texture, color_band); + vec4 color = transfer_function * density_scale; +#endif gl_FragColor = color; } diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index b8ed780397f..d58340965a7 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -1763,20 +1763,15 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime) } // if at least one tree, create the scenes from the PoseTree stored in the channels // postpone until execute_tree: this way the pose constraint are included - //if (count) - // create_scene(scene, ob, ctime); - //itasc_update_param(ob->pose); + if (count) + create_scene(scene, ob, ctime); + itasc_update_param(ob->pose); // make sure we don't rebuilt until the user changes something important ob->pose->flag &= ~POSE_WAS_REBUILT; } void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) { - if (!ob->pose->ikdata) { - // IK tree not yet created, no it now - create_scene(scene, ob, ctime); - itasc_update_param(ob->pose); - } if (ob->pose->ikdata) { IK_Data *ikdata = (IK_Data *)ob->pose->ikdata; bItasc *ikparam = (bItasc *) ob->pose->ikparam; diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h index 5d76ffe57b5..381ee5d40e5 100644 --- a/source/blender/makesdna/DNA_rigidbody_types.h +++ b/source/blender/makesdna/DNA_rigidbody_types.h @@ -226,10 +226,16 @@ typedef struct RigidBodyCon { float spring_stiffness_x; float spring_stiffness_y; float spring_stiffness_z; + float spring_stiffness_ang_x; + float spring_stiffness_ang_y; + float spring_stiffness_ang_z; /* amount of velocity lost over time */ float spring_damping_x; float spring_damping_y; float spring_damping_z; + float spring_damping_ang_x; + float spring_damping_ang_y; + float spring_damping_ang_z; /* motor settings */ float motor_lin_target_velocity; /* linear velocity the motor tries to hold */ @@ -295,7 +301,11 @@ typedef enum eRigidBodyCon_Flag { RBC_FLAG_USE_SPRING_Z = (1 << 13), /* motors */ RBC_FLAG_USE_MOTOR_LIN = (1 << 14), - RBC_FLAG_USE_MOTOR_ANG = (1 << 15) + RBC_FLAG_USE_MOTOR_ANG = (1 << 15), + /* angular springs */ + RBC_FLAG_USE_SPRING_ANG_X = (1 << 16), + RBC_FLAG_USE_SPRING_ANG_Y = (1 << 17), + RBC_FLAG_USE_SPRING_ANG_Z = (1 << 18) } eRigidBodyCon_Flag; /* ******************************** */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 9b0781ebe70..f5e71ae59a9 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1103,7 +1103,7 @@ typedef struct Sculpt { float gravity_factor; /* scale for constant detail size */ - float constant_detail; + float constant_detail; /* Constant detail resolution (Blender unit / constant_detail) */ float detail_percent; float pad; diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index 8f197c8c42c..fb81e2b6402 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -77,6 +77,23 @@ enum { VECTOR_DRAW_STREAMLINE = 1, }; +enum { + FLUID_FIELD_DENSITY = 0, + FLUID_FIELD_HEAT = 1, + FLUID_FIELD_FUEL = 2, + FLUID_FIELD_REACT = 3, + FLUID_FIELD_FLAME = 4, + FLUID_FIELD_VELOCITY_X = 5, + FLUID_FIELD_VELOCITY_Y = 6, + FLUID_FIELD_VELOCITY_Z = 7, + FLUID_FIELD_COLOR_R = 8, + FLUID_FIELD_COLOR_G = 9, + FLUID_FIELD_COLOR_B = 10, + FLUID_FIELD_FORCE_X = 11, + FLUID_FIELD_FORCE_Y = 12, + FLUID_FIELD_FORCE_Z = 13, +}; + /* cache compression */ #define SM_CACHE_LIGHT 0 #define SM_CACHE_HEAVY 1 @@ -193,9 +210,13 @@ typedef struct SmokeDomainSettings { float slice_per_voxel; float slice_depth; float display_thickness; + + struct ColorBand *coba; float vector_scale; char vector_draw_type; - char pad2[3]; + char use_coba; + char coba_field; /* simulation field used for the color mapping */ + char pad2; char cache_filename[1024]; } SmokeDomainSettings; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 280ad4aa9b1..5174c957834 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -35,6 +35,7 @@ #include "BLI_utildefines.h" #include "BKE_icons.h" +#include "BKE_object.h" #include "RNA_access.h" #include "RNA_define.h" @@ -347,6 +348,20 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) } } +static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_proxy) +{ + /* Special case, as we can't rely on id_make_local(); it clears proxies. */ + if (!clear_proxy && GS(self->name) == ID_OB) { + BKE_object_make_local_ex(bmain, (Object *)self, false, clear_proxy); + } + else { + id_make_local(bmain, self, false, false); + } + + return self->newid ? self->newid : self; +} + + static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain) { AnimData *adt = BKE_animdata_add_id(id); @@ -999,6 +1014,17 @@ static void rna_def_ID(BlenderRNA *brna) parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + func = RNA_def_function(srna, "make_local", "rna_ID_make_local"); + RNA_def_function_ui_description(func, "Make this datablock local, return local one " + "(may be a copy of the original, in case it is also indirectly used)"); + RNA_def_function_flag(func, FUNC_USE_MAIN); + RNA_def_boolean(func, "clear_proxy", true, "", + "Whether to clear proxies (the default behavior); can cause proxies to be duplicated" + " when still referred to from another library"); + RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL); + parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied"); + RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID"); RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one"); parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages"); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index cc290eab59d..594c1752328 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -585,7 +585,7 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this camera before deleting it " "(WARNING: will also delete objects instancing that camera data)"); @@ -624,7 +624,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this scene before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -665,7 +665,7 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -702,7 +702,7 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -746,7 +746,7 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -805,7 +805,7 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mesh before deleting it " "(WARNING: will also delete objects instancing that mesh data)"); @@ -845,7 +845,7 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lamp before deleting it " "(WARNING: will also delete objects instancing that lamp data)"); @@ -963,7 +963,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1000,7 +1000,7 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lattice before deleting it " "(WARNING: will also delete objects instancing that lattice data)"); @@ -1040,7 +1040,7 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this curve before deleting it " "(WARNING: will also delete objects instancing that curve data)"); @@ -1078,7 +1078,7 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this metaball before deleting it " "(WARNING: will also delete objects instancing that metaball data)"); @@ -1118,7 +1118,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1156,7 +1156,7 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1193,7 +1193,7 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1230,7 +1230,7 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "world", "World", "", "World to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1267,7 +1267,7 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1304,7 +1304,7 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this speaker before deleting it " "(WARNING: will also delete objects instancing that speaker data)"); @@ -1343,7 +1343,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1393,7 +1393,7 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1430,7 +1430,7 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this armature before deleting it " "(WARNING: will also delete objects instancing that armature data)"); @@ -1468,7 +1468,7 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1504,7 +1504,7 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of those particle settings before deleting them"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of those particle settings before deleting them"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1540,7 +1540,7 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1610,7 +1610,7 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1639,7 +1639,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1691,7 +1691,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1728,7 +1728,7 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index bdf001ed0e1..85a34a94746 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -507,6 +507,45 @@ static void rna_RigidBodyCon_spring_stiffness_z_set(PointerRNA *ptr, float value #endif } +static void rna_RigidBodyCon_spring_stiffness_ang_x_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_stiffness_ang_x = value; + +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) { + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value); + } +#endif +} + +static void rna_RigidBodyCon_spring_stiffness_ang_y_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_stiffness_ang_y = value; + +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) { + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value); + } +#endif +} + +static void rna_RigidBodyCon_spring_stiffness_ang_z_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_stiffness_ang_z = value; + +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) { + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value); + } +#endif +} + static void rna_RigidBodyCon_spring_damping_x_set(PointerRNA *ptr, float value) { RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; @@ -544,6 +583,43 @@ static void rna_RigidBodyCon_spring_damping_z_set(PointerRNA *ptr, float value) #endif } +static void rna_RigidBodyCon_spring_damping_ang_x_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_damping_ang_x = value; + +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) { + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value); + } +#endif +} + +static void rna_RigidBodyCon_spring_damping_ang_y_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_damping_ang_y = value; +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) { + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value); + } +#endif +} + +static void rna_RigidBodyCon_spring_damping_ang_z_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_damping_ang_z = value; +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) { + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value); + } +#endif +} + static void rna_RigidBodyCon_motor_lin_max_impulse_set(PointerRNA *ptr, float value) { RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; @@ -1061,6 +1137,21 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Z Spring", "Enable spring on Z axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "use_spring_ang_x", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_X); + RNA_def_property_ui_text(prop, "X Angle Spring", "Enable spring on X rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_spring_ang_y", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_Y); + RNA_def_property_ui_text(prop, "Y Angle Spring", "Enable spring on Y rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_spring_ang_z", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_Z); + RNA_def_property_ui_text(prop, "Z Angle Spring", "Enable spring on Z rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "use_motor_lin", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_MOTOR_LIN); RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_motor_lin_set"); @@ -1178,6 +1269,33 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Z Axis Stiffness", "Stiffness on the Z axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "spring_stiffness_ang_x", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_x"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_float_default(prop, 10.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_x_set", NULL); + RNA_def_property_ui_text(prop, "X Angle Stiffness", "Stiffness on the X rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "spring_stiffness_ang_y", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_y"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_float_default(prop, 10.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_y_set", NULL); + RNA_def_property_ui_text(prop, "Y Angle Stiffness", "Stiffness on the Y rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "spring_stiffness_ang_z", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_z"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_float_default(prop, 10.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_z_set", NULL); + RNA_def_property_ui_text(prop, "Z Angle Stiffness", "Stiffness on the Z rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "spring_damping_x", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "spring_damping_x"); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -1202,6 +1320,30 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Damping Z", "Damping on the Z axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "spring_damping_ang_x", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_x"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_x_set", NULL); + RNA_def_property_ui_text(prop, "Damping X Angle", "Damping on the X rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "spring_damping_ang_y", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_y"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_y_set", NULL); + RNA_def_property_ui_text(prop, "Damping Y Angle", "Damping on the Y rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "spring_damping_ang_z", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_z"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_z_set", NULL); + RNA_def_property_ui_text(prop, "Damping Z Angle", "Damping on the Z rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "motor_lin_target_velocity", PROP_FLOAT, PROP_UNIT_VELOCITY); RNA_def_property_float_sdna(prop, NULL, "motor_lin_target_velocity"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index e169ef0d822..7f405f0fb1f 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -600,10 +600,12 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Detail Percentage", "Maximum edge length for dynamic topology sculpting (in brush percenage)"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "constant_detail", PROP_FLOAT, PROP_PERCENTAGE); - RNA_def_property_range(prop, 0.001, 10000.0); - RNA_def_property_ui_range(prop, 0.1, 100.0, 10, 2); - RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (as percentage of blender unit)"); + prop = RNA_def_property(srna, "constant_detail_resolution", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "constant_detail"); + RNA_def_property_range(prop, 0.0001, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001, 1000.0, 10, 2); + RNA_def_property_ui_text(prop, "Resolution", "Maximum edge length for dynamic topology sculpting (as divisor " + "of blender unit - higher value means smaller edge length)"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "use_smooth_shading", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index ce18c86b8d0..15950e67671 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -30,6 +30,7 @@ #include <limits.h> #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -53,6 +54,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_particle.h" +#include "BKE_texture.h" #include "smoke_API.h" @@ -383,13 +385,24 @@ static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value) rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name)); } +static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, int value) +{ + SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; + + sds->use_coba = value; + + if (value && sds->coba == NULL) { + sds->coba = add_colorband(false); + } +} + static void rna_SmokeModifier_cache_filename_get(PointerRNA *ptr, char *filename) { - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - PTCacheID pid; + SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; + PTCacheID pid; - BKE_ptcache_id_from_smoke(&pid, ptr->id.data, sds->smd); - ptcache_filename(&pid, filename, sds->smd->time, 1, 1); + BKE_ptcache_id_from_smoke(&pid, ptr->id.data, sds->smd); + ptcache_filename(&pid, filename, sds->smd->time, 1, 1); } #else @@ -815,6 +828,41 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + /* --------- Color mapping. --------- */ + + prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set"); + RNA_def_property_ui_text(prop, "Use Color Ramp", + "Render a simulation field while mapping its voxels values to the colors of a ramp"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + static EnumPropertyItem coba_field_items[] = { + {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"}, + {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"}, + {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"}, + {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"}, + {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"}, + {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"}, + {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"}, + {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"}, + {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"}, + {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"}, + {0, NULL, 0, NULL, NULL} + }; + + prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "coba_field"); + RNA_def_property_enum_items(prop, coba_field_items); + RNA_def_property_ui_text(prop, "Field", "Simulation field to color map"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "coba"); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Color Ramp", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + prop = RNA_def_property(srna, "cache_filename", PROP_STRING, PROP_NONE); RNA_def_property_string_maxlength(prop, 1024); RNA_def_property_string_funcs(prop, "rna_SmokeModifier_cache_filename_get", NULL, NULL); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index ffcf12edb2d..b262e6412e3 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1980,7 +1980,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna) static EnumPropertyItem other_uv_filter_items[] = { {SI_FILTER_ALL, "ALL", 0, "All", "No filter, show all islands from other objects"}, {SI_FILTER_SAME_IMAGE, "SAME_IMAGE", ICON_IMAGE_DATA, "Same Image", - "Only show others' UV islads who's active image matches image of the active face"}, + "Only show others' UV islands whose active image matches image of the active face"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 8ad016007f4..10807c32b91 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -52,15 +52,6 @@ #include "BLT_lang.h" #include "GPU_buffers.h" -#ifdef WITH_CYCLES -static EnumPropertyItem compute_device_type_items[] = { - {USER_COMPUTE_DEVICE_NONE, "NONE", 0, "None", "Don't use compute device"}, - {USER_COMPUTE_DEVICE_CUDA, "CUDA", 0, "CUDA", "Use CUDA for GPU acceleration"}, - {USER_COMPUTE_DEVICE_OPENCL, "OPENCL", 0, "OpenCL", "Use OpenCL for GPU acceleration"}, - { 0, NULL, 0, NULL, NULL} -}; -#endif - #ifdef WITH_OPENSUBDIV static EnumPropertyItem opensubdiv_compute_type_items[] = { {USER_OPENSUBDIV_COMPUTE_NONE, "NONE", 0, "None", ""}, @@ -124,8 +115,6 @@ static EnumPropertyItem rna_enum_language_default_items[] = { #include "UI_interface.h" -#include "CCL_api.h" - #ifdef WITH_OPENSUBDIV # include "opensubdiv_capi.h" #endif @@ -476,78 +465,6 @@ static PointerRNA rna_Theme_space_list_generic_get(PointerRNA *ptr) } -#ifdef WITH_CYCLES -static EnumPropertyItem *rna_userdef_compute_device_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem *item = NULL; - int totitem = 0; - - /* add supported device types */ - RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_NONE); - if (CCL_compute_device_list(0)) - RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_CUDA); - if (CCL_compute_device_list(1)) - RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_OPENCL); - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} - -static int rna_userdef_compute_device_get(PointerRNA *UNUSED(ptr)) -{ - if (U.compute_device_type == USER_COMPUTE_DEVICE_NONE) - return 0; - - return U.compute_device_id; -} - -static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem tmp = {0, "", 0, "", ""}; - EnumPropertyItem *item = NULL; - int totitem = 0; - - if (U.compute_device_type == USER_COMPUTE_DEVICE_NONE) { - /* only add a single CPU device */ - tmp.value = 0; - tmp.name = "CPU"; - tmp.identifier = "CPU"; - RNA_enum_item_add(&item, &totitem, &tmp); - } - else { - /* get device list from cycles. it would be good to make this generic - * once we have more subsystems using opencl, for now this is easiest */ - int opencl = (U.compute_device_type == USER_COMPUTE_DEVICE_OPENCL); - CCLDeviceInfo *devices = CCL_compute_device_list(opencl); - int a; - - if (devices) { - for (a = 0; devices[a].identifier[0]; a++) { - tmp.value = devices[a].value; - tmp.identifier = devices[a].identifier; - tmp.name = devices[a].name; - RNA_enum_item_add(&item, &totitem, &tmp); - } - } - else { - tmp.value = 0; - tmp.name = "CPU"; - tmp.identifier = "CPU"; - RNA_enum_item_add(&item, &totitem, &tmp); - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} -#endif - #ifdef WITH_OPENSUBDIV static EnumPropertyItem *rna_userdef_opensubdiv_compute_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) @@ -3977,13 +3894,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; -#ifdef WITH_CYCLES - static EnumPropertyItem compute_device_items[] = { - {0, "CPU", 0, "CPU", ""}, - { 0, NULL, 0, NULL, NULL} - }; -#endif - static EnumPropertyItem image_draw_methods[] = { {IMAGE_DRAW_METHOD_2DTEXTURE, "2DTEXTURE", 0, "2D Texture", "Use CPU for display transform and draw image with 2D texture"}, {IMAGE_DRAW_METHOD_GLSL, "GLSL", 0, "GLSL", "Use GLSL shaders for display transform and draw image with 2D texture"}, @@ -4275,23 +4185,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) "Draw tool/property regions over the main region, when using Triple Buffer"); RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); -#ifdef WITH_CYCLES - prop = RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE); - RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); - RNA_def_property_enum_sdna(prop, NULL, "compute_device_type"); - RNA_def_property_enum_items(prop, compute_device_type_items); - RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_userdef_compute_device_type_itemf"); - RNA_def_property_ui_text(prop, "Compute Device Type", "Device to use for computation (rendering with Cycles)"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL); - - prop = RNA_def_property(srna, "compute_device", PROP_ENUM, PROP_NONE); - RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); - RNA_def_property_enum_sdna(prop, NULL, "compute_device_id"); - RNA_def_property_enum_items(prop, compute_device_items); - RNA_def_property_enum_funcs(prop, "rna_userdef_compute_device_get", NULL, "rna_userdef_compute_device_itemf"); - RNA_def_property_ui_text(prop, "Compute Device", "Device to use for computation"); -#endif - #ifdef WITH_OPENSUBDIV prop = RNA_def_property(srna, "opensubdiv_compute_type", PROP_ENUM, PROP_NONE); RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 90081a93188..35c9c9bcc89 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -419,6 +419,7 @@ static EnumPropertyItem keymap_modifiers_items[] = { static EnumPropertyItem operator_flag_items[] = { {OPTYPE_REGISTER, "REGISTER", 0, "Register", "Display in the info window and support the redo toolbar panel"}, {OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"}, + {OPTYPE_UNDO_GROUPED, "UNDO_GROUPED", 0, "Grouped Undo", "Push a single undo event for repetead instances of this operator"}, {OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"}, {OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"}, {OPTYPE_GRAB_CURSOR, "GRAB_CURSOR", 0, "Grab Pointer", @@ -1139,6 +1140,7 @@ static char _operator_idname[OP_MAX_TYPENAME]; static char _operator_name[OP_MAX_TYPENAME]; static char _operator_descr[RNA_DYN_DESCR_MAX]; static char _operator_ctxt[RNA_DYN_DESCR_MAX]; +static char _operator_undo_group[OP_MAX_TYPENAME]; static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { @@ -1153,10 +1155,11 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */ dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */ dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr); /* clear in case they are left unset */ - _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0'; + _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0'; /* We have to set default op context! */ strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); @@ -1210,9 +1213,10 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * int namelen = strlen(_operator_name) + 1; int desclen = strlen(_operator_descr) + 1; int ctxtlen = strlen(_operator_ctxt) + 1; + int ugrouplen = strlen(_operator_undo_group) + 1; char *ch; /* 2 terminators and 3 to convert a.b -> A_OT_b */ - ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname"); + ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname"); WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */ dummyot.idname = ch; ch += idlen; @@ -1224,6 +1228,9 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * ch += desclen; strcpy(ch, _operator_ctxt); dummyot.translation_context = ch; + ch += ctxtlen; + strcpy(ch, _operator_undo_group); + dummyot.undo_group = ch; } } @@ -1280,10 +1287,11 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */ dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */ dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr); /* clear in case they are left unset */ - _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0'; + _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0'; /* We have to set default op context! */ strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); @@ -1297,9 +1305,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v int namelen = strlen(_operator_name) + 1; int desclen = strlen(_operator_descr) + 1; int ctxtlen = strlen(_operator_ctxt) + 1; + int ugrouplen = strlen(_operator_undo_group) + 1; char *ch; /* 2 terminators and 3 to convert a.b -> A_OT_b */ - ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname"); + ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname"); WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */ dummyot.idname = ch; ch += idlen; @@ -1311,6 +1320,9 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v ch += desclen; strcpy(ch, _operator_ctxt); dummyot.translation_context = ch; + ch += ctxtlen; + strcpy(ch, _operator_undo_group); + dummyot.undo_group = ch; } if (strlen(identifier) >= sizeof(dummyop.idname)) { @@ -1401,6 +1413,16 @@ static void rna_Operator_bl_description_set(PointerRNA *ptr, const char *value) assert(!"setting the bl_description on a non-builtin operator"); } +static void rna_Operator_bl_undo_group_set(PointerRNA *ptr, const char *value) +{ + wmOperator *data = (wmOperator *)(ptr->data); + char *str = (char *)data->type->undo_group; + if (!str[0]) + BLI_strncpy(str, value, OP_MAX_TYPENAME); /* utf8 already ensured */ + else + assert(!"setting the bl_undo_group on a non-builtin operator"); +} + static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { wmKeyMapItem *kmi = ptr->data; @@ -1509,6 +1531,14 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->undo_group"); + RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */ + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set"); + /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->flag"); RNA_def_property_enum_items(prop, operator_flag_items); @@ -1587,6 +1617,14 @@ static void rna_def_macro_operator(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->undo_group"); + RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */ + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set"); + /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->flag"); RNA_def_property_enum_items(prop, operator_flag_items); diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index ecbc3891e8c..b049457e640 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -143,17 +143,17 @@ static void updateDepsgraph(ModifierData *md, { ArrayModifierData *amd = (ArrayModifierData *)md; if (amd->start_cap != NULL) { - DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap"); + DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap"); } if (amd->end_cap != NULL) { - DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap"); + DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap"); } if (amd->curve_ob) { - DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve"); + DEG_add_object_relation(node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve"); DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH); } if (amd->offset_ob != NULL) { - DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier Offset"); + DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset"); } } diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 83c4ca7984c..9186b10d8ca 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -145,12 +145,9 @@ static void updateDepsgraph(ModifierData *md, HookModifierData *hmd = (HookModifierData *)md; if (hmd->object != NULL) { if (hmd->subtarget[0]) { - DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier"); } - else { - DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); - } + DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); } /* We need own transformation as well. */ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 1d951bae48b..b20c03bee28 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -2233,7 +2233,7 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) } /* check if the face exists */ - if (BM_face_exists(vert_array, vert_seq_len, NULL)) { + if (BM_face_exists(vert_array, vert_seq_len) != NULL) { PyErr_SetString(PyExc_ValueError, "faces.new(verts): face already exists"); goto cleanup; @@ -2426,7 +2426,8 @@ static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args) return NULL; } - if (BM_face_exists(vert_array, vert_seq_len, &f)) { + f = BM_face_exists(vert_array, vert_seq_len); + if (f != NULL) { ret = BPy_BMFace_CreatePyObject(bm, f); } else { diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index ec69abbb1df..15f3c665fcf 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -33,6 +33,7 @@ #include <stddef.h> #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_string.h" #include "BLI_linklist.h" #include "BLI_path_util.h" @@ -405,6 +406,8 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) BLO_blendhandle_close(self->blo_handle); self->blo_handle = NULL; + GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__); + /* copied from wm_operator.c */ { /* mark all library linked objects to be updated */ @@ -412,7 +415,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* append, rather than linking */ if ((self->flag & FILE_LINK) == 0) { - BKE_library_make_local(bmain, lib, true, false); + BKE_library_make_local(bmain, lib, old_to_new_ids, true, false); } } @@ -439,6 +442,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) ID *id; id = PyCapsule_GetPointer(item, NULL); + id = BLI_ghash_lookup_default(old_to_new_ids, id, id); Py_DECREF(item); RNA_id_pointer_create(id, &id_ptr); @@ -452,6 +456,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) } #endif /* USE_RNA_DATABLOCKS */ + BLI_ghash_free(old_to_new_ids, NULL, NULL); Py_RETURN_NONE; } } diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 9dec2698720..3d6462e09a0 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -2064,11 +2064,13 @@ static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[ if (lar->mode & LA_SHAD_TEX) do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX); - lamp_get_shadow(lar, shi, inp, shadfac, shi->depth); + if (R.r.mode & R_SHADOW) { + lamp_get_shadow(lar, shi, inp, shadfac, shi->depth); - shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0])); - shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1])); - shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2])); + shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0])); + shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1])); + shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2])); + } } return visifac; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 0fe3e8a0fcf..cd46e24264d 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -138,6 +138,7 @@ enum { OPTYPE_INTERNAL = (1 << 6), OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */ + OPTYPE_UNDO_GROUPED = (1 << 8), /* Special type of undo which doesn't store itself multiple times */ }; /* context to call operator in for WM_operator_name_call */ @@ -522,6 +523,7 @@ typedef struct wmOperatorType { const char *idname; /* unique identifier */ const char *translation_context; const char *description; /* tooltips and python docs */ + const char *undo_group; /* identifier to group operators together */ /* this callback executes the operator without any interactive input, * parameters may be provided through operator properties. cannot use diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index dc34e8015c9..d2b0acd836b 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -727,10 +727,13 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat) /* we don't want to do undo pushes for operators that are being * called from operators that already do an undo push. usually * this will happen for python operators that call C operators */ - if (wm->op_undo_depth == 0) + if (wm->op_undo_depth == 0) { if (op->type->flag & OPTYPE_UNDO) ED_undo_push_op(C, op); - + else if (op->type->flag & OPTYPE_UNDO_GROUPED) + ED_undo_grouped_push_op(C, op); + } + if (repeat == 0) { if (G.debug & G_DEBUG_WM) { char *buf = WM_operator_pystring(C, op, false, true); @@ -1854,9 +1857,12 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand wm->op_undo_depth--; /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */ - if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) + if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) { if (handler->op->type->flag & OPTYPE_UNDO) ED_undo_push_op(C, handler->op); + else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED) + ED_undo_grouped_push_op(C, handler->op); + } if (handler->op->reports->list.first) { diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index e872ec1a524..3b733f9558c 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -419,7 +419,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive"); if (use_recursive) { - BKE_library_make_local(bmain, NULL, true, set_fake); + BKE_library_make_local(bmain, NULL, NULL, true, set_fake); } else { LinkNode *itemlink; @@ -430,7 +430,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id; if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) { - BKE_library_make_local(bmain, new_id->lib, true, set_fake); + BKE_library_make_local(bmain, new_id->lib, NULL, true, set_fake); BLI_gset_insert(done_libraries, new_id->lib); } } diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index d8a4ddc8d4f..6040dfff644 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -142,7 +142,6 @@ struct wmWindowManager; # pragma GCC diagnostic ignored "-Wunused-parameter" #endif -#include "../../intern/cycles/blender/CCL_api.h" #include "../../intern/dualcon/dualcon.h" #include "../../intern/elbeem/extern/elbeem.h" #include "../blender/blenkernel/BKE_modifier.h" @@ -770,10 +769,6 @@ void *dualcon(const DualConInput *input_mesh, float scale, int depth) RET_ZERO -/* intern/cycles */ -struct CCLDeviceInfo; -struct CCLDeviceInfo *CCL_compute_device_list(int opencl) RET_NULL - /* compositor */ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering, const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index f65688e1304..10af0d5489e 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1153,13 +1153,12 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE) COMPONENT Blender DESTINATION "." ) - + if(CMAKE_CL_64) + set(_WIN_PLATFORM x64) + else() + set(_WIN_PLATFORM x86) + endif() if(MSVC12_REDIST_DIR) - if(CMAKE_CL_64) - set(_WIN_PLATFORM x64) - else() - set(_WIN_PLATFORM x86) - endif() install( FILES ${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.CRT/msvcp120.dll @@ -1173,4 +1172,51 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE) ) endif() endif() + + if(MSVC14_REDIST_DIR) + set(KITSDIRx86 "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/10/") + set(KITSDIR "$ENV{ProgramFiles}/Windows Kits/10/") + if(IS_DIRECTORY ${KITSDIR}) + set(KITSPATH "${KITSDIR}/Redist/ucrt/DLLs/${_WIN_PLATFORM}") + else() + if(IS_DIRECTORY ${KITSDIRx86}) + set(KITSPATH "${KITSDIRx86}/Redist/ucrt/DLLs/${_WIN_PLATFORM}") + else() + message(FATAL_ERROR "Windows 10 SDK directory not found") + endif() + endif() + + install( + FILES + ${KITSPATH}/api-ms-win-core-file-l1-2-0.dll + ${KITSPATH}/api-ms-win-core-file-l2-1-0.dll + ${KITSPATH}/api-ms-win-core-localization-l1-2-0.dll + ${KITSPATH}/api-ms-win-core-processthreads-l1-1-0.dll + ${KITSPATH}/api-ms-win-core-processthreads-l1-1-1.dll + ${KITSPATH}/api-ms-win-core-synch-l1-1-0.dll + ${KITSPATH}/api-ms-win-core-synch-l1-2-0.dll + ${KITSPATH}/api-ms-win-core-timezone-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-conio-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-convert-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-environment-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-filesystem-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-heap-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-locale-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-math-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-process-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-runtime-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-stdio-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-string-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-time-l1-1-0.dll + ${KITSPATH}/ucrtbase.dll + ${MSVC14_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC140.CRT/vcruntime140.dll + DESTINATION "." + ) + if(WITH_OPENMP) + install( + FILES ${MSVC14_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC140.OpenMP/vcomp140.dll + DESTINATION "." + ) + endif() + endif() endif() diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp index 4f5e34896fc..c588a4b33cf 100644 --- a/source/gameengine/VideoTexture/VideoDeckLink.cpp +++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp @@ -544,12 +544,12 @@ HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/, ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void) { - return atomic_add_uint32(&mRefCount, 1U); + return atomic_add_and_fetch_uint32(&mRefCount, 1U); } ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void) { - uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U); + uint32_t newCount = atomic_sub_and_fetch_uint32(&mRefCount, 1U); if (newCount == 0) delete this; return (ULONG)newCount; |