From 91d882a8c9e43d1b274718ee827e6f14d960ab47 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 11 Aug 2017 17:51:38 +1000 Subject: [PATCH 01/14] RNA: Use hash lookups for structs Adding structs was checking for duplicates causing approx 75k string comparisons on startup. While overall speedup is minimal, Python access to `bpy.types` will now use a hash lookup instead of a full linked list search. See D2774 --- source/blender/makesrna/intern/makesrna.c | 20 +++++++----- source/blender/makesrna/intern/rna_access.c | 13 ++++---- source/blender/makesrna/intern/rna_define.c | 31 +++++++++++++------ .../makesrna/intern/rna_internal_types.h | 3 ++ source/blender/makesrna/intern/rna_rna.c | 24 +++++++------- 5 files changed, 57 insertions(+), 34 deletions(-) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index de436172bfd..9471d0e3fcf 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -2583,17 +2583,23 @@ static void rna_generate_blender(BlenderRNA *brna, FILE *f) { StructRNA *srna; - fprintf(f, "BlenderRNA BLENDER_RNA = {"); - + fprintf(f, + "BlenderRNA BLENDER_RNA = {\n" + "\t.structs = {" + ); srna = brna->structs.first; - if (srna) fprintf(f, "{&RNA_%s, ", srna->identifier); - else fprintf(f, "{NULL, "); + if (srna) fprintf(f, "&RNA_%s, ", srna->identifier); + else fprintf(f, "NULL, "); srna = brna->structs.last; - if (srna) fprintf(f, "&RNA_%s}", srna->identifier); - else fprintf(f, "NULL}"); + if (srna) fprintf(f, "&RNA_%s},\n", srna->identifier); + else fprintf(f, "NULL},\n"); - fprintf(f, "};\n\n"); + fprintf(f, + "\t.structs_map = NULL,\n" + "\t.structs_len = 0,\n" + "};\n\n" + ); } static void rna_generate_property_prototypes(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE *f) diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 5a4db47d281..89348bb8f6c 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -76,6 +76,9 @@ void RNA_init(void) StructRNA *srna; PropertyRNA *prop; + BLENDER_RNA.structs_map = BLI_ghash_str_new_ex(__func__, 2048); + BLENDER_RNA.structs_len = 0; + for (srna = BLENDER_RNA.structs.first; srna; srna = srna->cont.next) { if (!srna->cont.prophash) { srna->cont.prophash = BLI_ghash_str_new("RNA_init gh"); @@ -86,6 +89,8 @@ void RNA_init(void) } } } + BLI_ghash_insert(BLENDER_RNA.structs_map, (void *)srna->identifier, srna); + BLENDER_RNA.structs_len += 1; } } @@ -513,13 +518,7 @@ static const char *rna_ensure_property_name(const PropertyRNA *prop) StructRNA *RNA_struct_find(const char *identifier) { - StructRNA *type; - if (identifier) { - for (type = BLENDER_RNA.structs.first; type; type = type->cont.next) - if (STREQ(type->identifier, identifier)) - return type; - } - return NULL; + return BLI_ghash_lookup(BLENDER_RNA.structs_map, identifier); } const char *RNA_struct_identifier(const StructRNA *type) diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 42c0344f46e..5a1aec59362 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -135,6 +135,19 @@ void rna_freelistN(ListBase *listbase) listbase->first = listbase->last = NULL; } +static void rna_brna_structs_add(BlenderRNA *brna, StructRNA *srna) +{ + rna_addtail(&brna->structs, srna); + brna->structs_len += 1; + + /* This exception is only needed for pre-processing. + * otherwise we don't allow empty names. */ + if (srna->identifier[0] != '\0') { + BLI_ghash_insert(brna->structs_map, (void *)srna->identifier, srna); + } + +} + StructDefRNA *rna_find_struct_def(StructRNA *srna) { StructDefRNA *dsrna; @@ -534,6 +547,8 @@ BlenderRNA *RNA_create(void) const char *error_message = NULL; BLI_listbase_clear(&DefRNA.structs); + brna->structs_map = BLI_ghash_str_new_ex(__func__, 2048); + DefRNA.error = 0; DefRNA.preprocess = 1; @@ -654,6 +669,9 @@ void RNA_free(BlenderRNA *brna) StructRNA *srna, *nextsrna; FunctionRNA *func; + BLI_ghash_free(brna->structs_map, NULL, NULL); + brna->structs_map = NULL; + if (DefRNA.preprocess) { RNA_define_free(brna); @@ -747,7 +765,7 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN if (!srnafrom) srna->icon = ICON_DOT; - rna_addtail(&brna->structs, srna); + rna_brna_structs_add(brna, srna); if (DefRNA.preprocess) { ds = MEM_callocN(sizeof(StructDefRNA), "StructDefRNA"); @@ -819,10 +837,8 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char * if (from) { /* find struct to derive from */ - for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next) - if (STREQ(srnafrom->identifier, from)) - break; - + /* Inline RNA_struct_find(...) because it wont link from here. */ + srnafrom = BLI_ghash_lookup(brna->structs_map, from); if (!srnafrom) { fprintf(stderr, "%s: struct %s not found to define %s.\n", __func__, from, identifier); DefRNA.error = 1; @@ -901,10 +917,7 @@ void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *struct StructRNA *srnafrom; /* find struct to derive from */ - for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next) - if (STREQ(srnafrom->identifier, structname)) - break; - + srnafrom = BLI_ghash_lookup(brna->structs_map, structname); if (!srnafrom) { fprintf(stderr, "%s: struct %s not found for %s.\n", __func__, structname, srna->identifier); DefRNA.error = 1; diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index df591659fdb..b52f6c78f3a 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -413,6 +413,9 @@ struct StructRNA { struct BlenderRNA { ListBase structs; + struct GHash *structs_map; + /* Needed because types with an empty identifier aren't included in 'structs_map'. */ + unsigned int structs_len; }; #define CONTAINER_RNA_ID(cont) (*(const char **)(((ContainerRNA *)(cont))+1)) diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index abded187b33..bbd0fe2486e 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -985,19 +985,22 @@ static int rna_Function_use_self_type_get(PointerRNA *ptr) static void rna_BlenderRNA_structs_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { - rna_iterator_listbase_begin(iter, &((BlenderRNA *)ptr->data)->structs, NULL); + BlenderRNA *brna = ptr->data; + rna_iterator_listbase_begin(iter, &brna->structs, NULL); } /* optional, for faster lookups */ static int rna_BlenderRNA_structs_length(PointerRNA *ptr) { - return BLI_listbase_count(&((BlenderRNA *)ptr->data)->structs); + BlenderRNA *brna = ptr->data; + BLI_assert(brna->structs_len == BLI_listbase_count(&brna->structs)); + return brna->structs_len; } static int rna_BlenderRNA_structs_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr) { - StructRNA *srna = BLI_findlink(&((BlenderRNA *)ptr->data)->structs, index); - - if (srna) { + BlenderRNA *brna = ptr->data; + StructRNA *srna = index < brna->structs_len ? BLI_findlink(&brna->structs, index) : NULL; + if (srna != NULL) { RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); return true; } @@ -1007,12 +1010,11 @@ static int rna_BlenderRNA_structs_lookup_int(PointerRNA *ptr, int index, Pointer } static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) { - StructRNA *srna = ((BlenderRNA *)ptr->data)->structs.first; - for (; srna; srna = srna->cont.next) { - if (key[0] == srna->identifier[0] && STREQ(key, srna->identifier)) { - RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); - return true; - } + BlenderRNA *brna = ptr->data; + StructRNA *srna = BLI_ghash_lookup(brna->structs_map, (void *)key); + if (srna != NULL) { + RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr); + return true; } return false; From d5d626df236b17c2d4ac731b2aaace52a2611304 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 11 Aug 2017 10:24:57 +0200 Subject: [PATCH 02/14] Fix T52344: Softbody on Text. For some reasons (c) softbody modifier was marked as compatible with curves... Would need much more work though, so for now just removing that flag! --- source/blender/modifiers/intern/MOD_softbody.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index a0bbe5da04a..f5fc1d8ced8 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -100,8 +100,7 @@ ModifierTypeInfo modifierType_Softbody = { /* structName */ "SoftbodyModifierData", /* structSize */ sizeof(SoftbodyModifierData), /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_AcceptsLattice | + /* flags */ eModifierTypeFlag_AcceptsLattice | eModifierTypeFlag_RequiresOriginalData | eModifierTypeFlag_Single, From bc88ee329256d903308e67071c2edc2c8f32376d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 11 Aug 2017 19:09:03 +1000 Subject: [PATCH 03/14] Error in last commit, problems with unregister We can't free the identifier before its used when removing from the ghash. --- source/blender/makesrna/intern/rna_define.c | 23 +++++++++++++++---- source/blender/makesrna/intern/rna_nodetree.c | 7 +++--- source/blender/makesrna/intern/rna_render.c | 2 +- source/blender/makesrna/intern/rna_ui.c | 10 ++++---- source/blender/makesrna/intern/rna_userdef.c | 2 +- source/blender/makesrna/intern/rna_wm.c | 3 ++- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 5a1aec59362..0f8bc19bd6c 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -145,9 +145,26 @@ static void rna_brna_structs_add(BlenderRNA *brna, StructRNA *srna) if (srna->identifier[0] != '\0') { BLI_ghash_insert(brna->structs_map, (void *)srna->identifier, srna); } - } +#ifdef RNA_RUNTIME +static void rna_brna_structs_remove_and_free(BlenderRNA *brna, StructRNA *srna) +{ + if (brna->structs_map) { + if (srna->identifier[0] != '\0') { + BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL); + } + } + + RNA_def_struct_free_pointers(srna); + + if (srna->flag & STRUCT_RUNTIME) { + rna_freelinkN(&brna->structs, srna); + } + brna->structs_len -= 1; +} +#endif + StructDefRNA *rna_find_struct_def(StructRNA *srna) { StructDefRNA *dsrna; @@ -655,10 +672,8 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna) rna_freelinkN(&srna->functions, func); } - RNA_def_struct_free_pointers(srna); - if (srna->flag & STRUCT_RUNTIME) - rna_freelinkN(&brna->structs, srna); + rna_brna_structs_remove_and_free(brna, srna); #else UNUSED_VARS(brna, srna); #endif diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 05b64c959a4..00b881dabc7 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -595,11 +595,10 @@ static void rna_NodeTree_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &nt->ext); + RNA_struct_free(&BLENDER_RNA, type); ntreeTypeFreeLink(nt); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } @@ -1348,11 +1347,11 @@ static void rna_Node_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &nt->ext); + RNA_struct_free(&BLENDER_RNA, type); /* this also frees the allocated nt pointer, no MEM_free call needed! */ nodeUnregisterType(nt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); @@ -1810,10 +1809,10 @@ static void rna_NodeSocket_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &st->ext_socket); + RNA_struct_free(&BLENDER_RNA, type); nodeUnregisterSocketType(st); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 44dcb72264a..c30765d8857 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -279,8 +279,8 @@ static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &et->ext); - BLI_freelinkN(&R_engines, et); RNA_struct_free(&BLENDER_RNA, type); + BLI_freelinkN(&R_engines, et); } static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, void *data, const char *identifier, diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 54b82fc89d6..64b41ac789f 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -177,9 +177,9 @@ static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &pt->ext); + RNA_struct_free(&BLENDER_RNA, type); BLI_freelinkN(&art->paneltypes, pt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); @@ -455,11 +455,10 @@ static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &ult->ext); + RNA_struct_free(&BLENDER_RNA, type); WM_uilisttype_freelink(ult); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } @@ -551,9 +550,9 @@ static void rna_Header_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &ht->ext); + RNA_struct_free(&BLENDER_RNA, type); BLI_freelinkN(&art->headertypes, ht); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); @@ -673,11 +672,10 @@ static void rna_Menu_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &mt->ext); + RNA_struct_free(&BLENDER_RNA, type); WM_menutype_freelink(mt); - RNA_struct_free(&BLENDER_RNA, type); - /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); } diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 350cb02223f..19a25b4df11 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -606,9 +606,9 @@ static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type) return; RNA_struct_free_extension(type, &apt->ext); + RNA_struct_free(&BLENDER_RNA, type); BKE_addon_pref_type_remove(apt); - RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index b5ecaf739c7..4aee03025f6 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1269,10 +1269,11 @@ static void rna_Operator_unregister(struct Main *bmain, StructRNA *type) idname = ot->idname; WM_operatortype_remove_ptr(ot); - MEM_freeN((void *)idname); /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */ RNA_struct_free(&BLENDER_RNA, type); + + MEM_freeN((void *)idname); } static void **rna_Operator_instance(PointerRNA *ptr) From 58ee7383104eeab627648efed0aaabbefd2870bc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 11 Aug 2017 19:04:41 +1000 Subject: [PATCH 04/14] GHash: note that 'deprecated' is used for private --- source/blender/blenlib/BLI_ghash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 7cf3e97bdc9..26769f9fe09 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -43,7 +43,7 @@ extern "C" { #ifndef GHASH_INTERNAL_API # ifdef __GNUC__ # undef _GHASH_INTERNAL_ATTR -# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated)) +# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated)) /* not deprecated, just private. */ # endif #endif From daa834bc116719ffc884905238969b98ac4eb2c9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 11 Aug 2017 20:09:22 +1000 Subject: [PATCH 05/14] RNA: Operators were excluded from struct map Recent changes meant structs that were registered without a name wouldn't get added to the map. Now assigning identifiers manages the struct-map. --- source/blender/blenkernel/intern/node.c | 2 +- source/blender/makesrna/RNA_define.h | 3 ++- source/blender/makesrna/intern/rna_define.c | 25 ++++++++++++++++++- .../blender/python/intern/bpy_operator_wrap.c | 10 +++++--- .../windowmanager/intern/wm_operators.c | 8 +++--- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index b11b328a01c..07fdd667425 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -2280,7 +2280,7 @@ StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create) /* rename the RNA type */ RNA_def_struct_free_pointers(srna); - RNA_def_struct_identifier(srna, identifier); + RNA_def_struct_identifier(&BLENDER_RNA, srna, identifier); RNA_def_struct_ui_text(srna, name, description); RNA_def_struct_duplicate_pointers(srna); } diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 6e62313b00a..b49cea0263b 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -62,7 +62,8 @@ void RNA_def_struct_refine_func(StructRNA *srna, const char *refine); void RNA_def_struct_idprops_func(StructRNA *srna, const char *refine); void RNA_def_struct_register_funcs(StructRNA *srna, const char *reg, const char *unreg, const char *instance); void RNA_def_struct_path_func(StructRNA *srna, const char *path); -void RNA_def_struct_identifier(StructRNA *srna, const char *identifier); +void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier); +void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier); void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description); void RNA_def_struct_ui_icon(StructRNA *srna, int icon); void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 0f8bc19bd6c..b10a2b33317 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -993,7 +993,30 @@ void RNA_def_struct_path_func(StructRNA *srna, const char *path) if (path) srna->path = (StructPathFunc)path; } -void RNA_def_struct_identifier(StructRNA *srna, const char *identifier) +void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier) +{ + if (DefRNA.preprocess) { + fprintf(stderr, "%s: only at runtime.\n", __func__); + return; + } + + /* Operator registration may set twice, see: operator_properties_init */ + if (identifier != srna->identifier) { + if (srna->identifier[0] != '\0') { + BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL); + } + if (identifier[0] != '\0') { + BLI_ghash_insert(brna->structs_map, (void *)identifier, srna); + } + } + + srna->identifier = identifier; +} + +/** + * Only used in one case when we name the struct for the purpose of useful error messages. + */ +void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier) { if (DefRNA.preprocess) { fprintf(stderr, "%s: only at runtime.\n", __func__); diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 90719905a79..9d57adca946 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -48,10 +48,12 @@ static void operator_properties_init(wmOperatorType *ot) PyTypeObject *py_class = ot->ext.data; RNA_struct_blender_type_set(ot->ext.srna, ot); - /* only call this so pyrna_deferred_register_class gives a useful error - * WM_operatortype_append_ptr will call RNA_def_struct_identifier - * later */ - RNA_def_struct_identifier(ot->srna, ot->idname); + /* Only call this so pyrna_deferred_register_class gives a useful error + * WM_operatortype_append_ptr will call RNA_def_struct_identifier later. + * + * Note the 'no_struct_map' function is used since the actual struct name is already used by the operator. + */ + RNA_def_struct_identifier_no_struct_map(ot->srna, ot->idname); if (pyrna_deferred_register_class(ot->srna, py_class) != 0) { PyErr_Print(); /* failed to register operator props */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index aa27254bbaa..cd3bebb48ee 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -177,7 +177,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *)) /* XXX All ops should have a description but for now allow them not to. */ RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } @@ -193,7 +193,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void * ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT; opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } @@ -398,7 +398,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam ot->description = UNDOCUMENTED_OPERATOR_TIP; RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); /* Use i18n context from ext.srna if possible (py operators). */ i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT; RNA_def_struct_translation_context(ot->srna, i18n_context); @@ -432,7 +432,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); - RNA_def_struct_identifier(ot->srna, ot->idname); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } From 59a52fef6cebac25a296a9c8cc76017bf471f7ee Mon Sep 17 00:00:00 2001 From: Aleksandr Zinovev Date: Fri, 11 Aug 2017 13:18:30 +0300 Subject: [PATCH 06/14] Pie menu's sub-rows ignore 'EXPAND' flag Regression, to be backported in 2.79. --- source/blender/editors/interface/interface_layout.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 804ffec7997..b4de3d0c5ef 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -247,7 +247,9 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X); if (variable) { - layout->item.flag |= UI_ITEM_MIN; + if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) { + layout->item.flag |= UI_ITEM_MIN; + } const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; /* it may seem odd that the icon only adds (UI_UNIT_X / 4) * but taking margins into account its fine */ From bd069a89aa3a2d166bc7cb4746a2b757497fdddc Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Aug 2017 09:33:18 +0200 Subject: [PATCH 07/14] Fix T52229: Shadow Catcher artifacts when under transparency Added some extra tirckery to avoid background being tinted dark with transparent surface. Maybe a bit hacky, but seems to work fine. --- intern/cycles/kernel/kernel_accumulate.h | 19 +++++++++++-------- intern/cycles/kernel/kernel_path.h | 15 ++++++++++----- intern/cycles/kernel/kernel_path_branched.h | 14 +++++++++++--- intern/cycles/kernel/kernel_shader.h | 4 ++-- intern/cycles/kernel/kernel_types.h | 4 ++-- ...out_emission_blurring_pathtermination_ao.h | 7 ++++--- 6 files changed, 40 insertions(+), 23 deletions(-) diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index 9ed16aceb55..d139e28b013 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -21,6 +21,9 @@ CCL_NAMESPACE_BEGIN * BSDF evaluation result, split per BSDF type. This is used to accumulate * render passes separately. */ +ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, + const ShaderData *sd); + ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 value, int use_light_pass) { #ifdef __PASSES__ @@ -223,6 +226,7 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) L->shadow_background_color = make_float3(0.0f, 0.0f, 0.0f); L->shadow_radiance_sum = make_float3(0.0f, 0.0f, 0.0f); L->shadow_throughput = 0.0f; + L->shadow_transparency = 1.0f; #endif #ifdef __DENOISING_FEATURES__ @@ -398,10 +402,11 @@ ccl_device_inline void path_radiance_accum_total_light( #endif } -ccl_device_inline void path_radiance_accum_background(PathRadiance *L, - ccl_addr_space PathState *state, - float3 throughput, - float3 value) +ccl_device_inline void path_radiance_accum_background( + PathRadiance *L, + ccl_addr_space PathState *state, + float3 throughput, + float3 value) { #ifdef __PASSES__ if(L->use_light_pass) { @@ -421,9 +426,7 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, #ifdef __SHADOW_TRICKS__ if(state->flag & PATH_RAY_STORE_SHADOW_INFO) { L->path_total += throughput * value; - if(state->flag & PATH_RAY_SHADOW_CATCHER_ONLY) { - L->path_total_shaded += throughput * value; - } + L->path_total_shaded += throughput * value * L->shadow_transparency; } #endif @@ -671,7 +674,7 @@ ccl_device_inline float path_radiance_sum_shadow(const PathRadiance *L) if(path_total != 0.0f) { return path_total_shaded / path_total; } - return 1.0f; + return L->shadow_transparency; } /* Calculate final light sum and transparency for shadow catcher object. */ diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 21564e81b7a..92b31d46697 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -320,8 +320,12 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #endif /* __BRANCHED_PATH__ */ #ifdef __SHADOW_TRICKS__ - if(!(sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) { - state->flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; + if(!(sd->object_flag & SD_OBJECT_SHADOW_CATCHER) && + (state->flag & PATH_RAY_SHADOW_CATCHER)) + { + /* Only update transparency after shadow catcher bounce. */ + L->shadow_transparency *= + average(shader_bsdf_transparency(kg, sd)); } #endif /* __SHADOW_TRICKS__ */ @@ -647,7 +651,6 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg, if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) { if(state.flag & PATH_RAY_CAMERA) { state.flag |= (PATH_RAY_SHADOW_CATCHER | - PATH_RAY_SHADOW_CATCHER_ONLY | PATH_RAY_STORE_SHADOW_INFO); if(!kernel_data.background.transparent) { L->shadow_background_color = @@ -657,8 +660,10 @@ ccl_device_inline float kernel_path_integrate(KernelGlobals *kg, L->shadow_throughput = average(throughput); } } - else { - state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; + else if(state.flag & PATH_RAY_SHADOW_CATCHER) { + /* Only update transparency after shadow catcher bounce. */ + L->shadow_transparency *= + average(shader_bsdf_transparency(kg, &sd)); } #endif /* __SHADOW_TRICKS__ */ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 4ec37d225f7..cea677fd701 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -119,6 +119,9 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba PathState ps = *state; float3 tp = throughput; Ray bsdf_ray; +#ifdef __SHADOW_TRICKS__ + float shadow_transparency = L->shadow_transparency; +#endif if(!kernel_branched_path_surface_bounce(kg, &bsdf_rng, @@ -149,6 +152,10 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba * for the next samples */ path_radiance_sum_indirect(L); path_radiance_reset_indirect(L); + +#ifdef __SHADOW_TRICKS__ + L->shadow_transparency = shadow_transparency; +#endif } } } @@ -500,7 +507,6 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, #ifdef __SHADOW_TRICKS__ if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) { state.flag |= (PATH_RAY_SHADOW_CATCHER | - PATH_RAY_SHADOW_CATCHER_ONLY | PATH_RAY_STORE_SHADOW_INFO); if(!kernel_data.background.transparent) { L->shadow_background_color = @@ -509,8 +515,10 @@ ccl_device float kernel_branched_path_integrate(KernelGlobals *kg, L->shadow_radiance_sum = path_radiance_clamp_and_sum(kg, L); L->shadow_throughput = average(throughput); } - else { - state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; + else if(state.flag & PATH_RAY_SHADOW_CATCHER) { + /* Only update transparency after shadow catcher bounce. */ + L->shadow_transparency *= + average(shader_bsdf_transparency(kg, &sd)); } #endif /* __SHADOW_TRICKS__ */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 90b936d83c9..f553599a2e4 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -669,7 +669,7 @@ ccl_device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughn } } -ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, ShaderData *sd) +ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, const ShaderData *sd) { if(sd->flag & SD_HAS_ONLY_VOLUME) return make_float3(1.0f, 1.0f, 1.0f); @@ -677,7 +677,7 @@ ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, ShaderData *sd) float3 eval = make_float3(0.0f, 0.0f, 0.0f); for(int i = 0; i < sd->num_closure; i++) { - ShaderClosure *sc = &sd->closure[i]; + const ShaderClosure *sc = &sd->closure[i]; if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID) // todo: make this work for osl eval += sc->weight; diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 90a3c818214..39840d265b2 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -351,8 +351,7 @@ enum PathRayFlag { PATH_RAY_DIFFUSE_ANCESTOR = (1 << 16), PATH_RAY_SINGLE_PASS_DONE = (1 << 17), PATH_RAY_SHADOW_CATCHER = (1 << 18), - PATH_RAY_SHADOW_CATCHER_ONLY = (1 << 19), - PATH_RAY_STORE_SHADOW_INFO = (1 << 20), + PATH_RAY_STORE_SHADOW_INFO = (1 << 19), }; /* Closure Label */ @@ -529,6 +528,7 @@ typedef ccl_addr_space struct PathRadiance { */ float3 shadow_radiance_sum; float shadow_throughput; + float shadow_transparency; #endif #ifdef __DENOISING_FEATURES__ diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h index 916b81faf4e..fe761305bfb 100644 --- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h +++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h @@ -127,7 +127,6 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( if(state->flag & PATH_RAY_CAMERA) { PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; state->flag |= (PATH_RAY_SHADOW_CATCHER | - PATH_RAY_SHADOW_CATCHER_ONLY | PATH_RAY_STORE_SHADOW_INFO); if(!kernel_data.background.transparent) { ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; @@ -141,8 +140,10 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( L->shadow_throughput = average(throughput); } } - else { - state->flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; + else if(state->flag & PATH_RAY_SHADOW_CATCHER) { + /* Only update transparency after shadow catcher bounce. */ + PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; + L->shadow_transparency *= average(shader_bsdf_transparency(kg, sd)); } #endif /* __SHADOW_TRICKS__ */ From 596ee4b50559eddcc16f01a8fa76e692aac157c1 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Aug 2017 09:34:34 +0200 Subject: [PATCH 08/14] Cycles tests: Draw images on top of checkerboard This way it's easier to see alpha-channel only images, such as shadow catcher images on transparent film. --- tests/python/cycles_render_tests.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index ffd8627dbf2..0b90ab5b55f 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -163,6 +163,25 @@ class Report: Cycles Test Report @@ -206,8 +225,8 @@ class Report: test_html = """ {}
{}
{} - - + + """ . format(style, name, self.testname, status, new_url, ref_url, new_url, From 2e25754ecdd7b2776b44f4089b3d427b28ca3c81 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Aug 2017 12:46:09 +0200 Subject: [PATCH 09/14] Cycles: Clarify new argument in PathRadiance --- intern/cycles/kernel/kernel_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 39840d265b2..d5f720778ff 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -528,6 +528,8 @@ typedef ccl_addr_space struct PathRadiance { */ float3 shadow_radiance_sum; float shadow_throughput; + + /* Accumulated transparency along the path after shadow catcher bounce. */ float shadow_transparency; #endif From 31be0a6e52e1070c50d413432210a3217249f5af Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 11 Aug 2017 14:25:36 +0200 Subject: [PATCH 10/14] Fix T52344: Softbody on Text. Own previous fix (rBd5d626df236b) was not valid, curves are actually supported by SoftBodies. It was rather a mere UI bug, which was not including Surfaces and Font obect types in those valid for softbody UI. Thanks to @brecht for the head up! Also, fix safe for 2.79, btw. --- release/scripts/startup/bl_ui/properties_physics_common.py | 2 +- release/scripts/startup/bl_ui/properties_physics_softbody.py | 5 ++++- source/blender/modifiers/intern/MOD_softbody.c | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index 0b98d8738dc..73d3d5fc755 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -79,7 +79,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel): col = split.column() - if obj.type in {'MESH', 'LATTICE', 'CURVE'}: + if obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE', 'FONT'}: physics_add(self, col, context.soft_body, "Soft Body", 'SOFT_BODY', 'MOD_SOFT', True) if obj.type == 'MESH': diff --git a/release/scripts/startup/bl_ui/properties_physics_softbody.py b/release/scripts/startup/bl_ui/properties_physics_softbody.py index 5ce4302891d..5efe105e7d8 100644 --- a/release/scripts/startup/bl_ui/properties_physics_softbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_softbody.py @@ -26,6 +26,9 @@ from bl_ui.properties_physics_common import ( ) +COMPAT_OB_TYPES = {'MESH', 'LATTICE', 'CURVE', 'SURFACE', 'FONT'} + + def softbody_panel_enabled(md): return (md.point_cache.is_baked is False) @@ -39,7 +42,7 @@ class PhysicButtonsPanel: def poll(cls, context): ob = context.object rd = context.scene.render - return (ob and (ob.type == 'MESH' or ob.type == 'LATTICE'or ob.type == 'CURVE')) and (rd.engine in cls.COMPAT_ENGINES) and (context.soft_body) + return ob and ob.type in COMPAT_OB_TYPES and rd.engine in cls.COMPAT_ENGINES and context.soft_body class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel): diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index f5fc1d8ced8..a0bbe5da04a 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -100,7 +100,8 @@ ModifierTypeInfo modifierType_Softbody = { /* structName */ "SoftbodyModifierData", /* structSize */ sizeof(SoftbodyModifierData), /* type */ eModifierTypeType_OnlyDeform, - /* flags */ eModifierTypeFlag_AcceptsLattice | + /* flags */ eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_AcceptsLattice | eModifierTypeFlag_RequiresOriginalData | eModifierTypeFlag_Single, From 30e83d58ff9b4c9251f8004346efd8c9a5d74787 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 11 Aug 2017 22:16:44 +1000 Subject: [PATCH 11/14] Object Apply Transform: option to apply properties In some cases users may want to disable this option to avoid changing other properties besides vertex locations. --- source/blender/blenkernel/BKE_curve.h | 4 +-- source/blender/blenkernel/BKE_mball.h | 2 +- source/blender/blenkernel/intern/curve.c | 18 ++++++++---- source/blender/blenkernel/intern/mball.c | 21 ++++++++------ .../blender/editors/armature/armature_edit.c | 28 ++++++++++--------- source/blender/editors/include/ED_armature.h | 6 ++-- .../blender/editors/object/object_transform.c | 20 +++++++++---- source/blender/makesrna/intern/rna_armature.c | 2 +- .../blender/makesrna/intern/rna_curve_api.c | 2 +- source/blender/makesrna/intern/rna_meta_api.c | 2 +- .../bad_level_call_stubs/stubs.c | 2 +- 11 files changed, 64 insertions(+), 43 deletions(-) diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index b6eea42724d..be05f7d4136 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -93,8 +93,8 @@ void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], fl bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]); bool BKE_curve_center_median(struct Curve *cu, float cent[3]); bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]); -void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], const bool do_keys, const float unit_scale); -void BKE_curve_transform(struct Curve *cu, float mat[4][4], const bool do_keys); +void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], const bool do_keys, const bool do_props, const float unit_scale); +void BKE_curve_transform(struct Curve *cu, float mat[4][4], const bool do_keys, const bool do_props); void BKE_curve_translate(struct Curve *cu, float offset[3], const bool do_keys); void BKE_curve_material_index_remove(struct Curve *cu, int index); void BKE_curve_material_index_clear(struct Curve *cu); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index a02a068b920..f02704ba903 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -60,7 +60,7 @@ bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3], float obmat[4][4], const short flag); bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]); bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]); -void BKE_mball_transform(struct MetaBall *mb, float mat[4][4]); +void BKE_mball_transform(struct MetaBall *mb, float mat[4][4], const bool do_props); void BKE_mball_translate(struct MetaBall *mb, const float offset[3]); struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index e08fdcf10e9..ece33786940 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -4442,7 +4442,9 @@ bool BKE_curve_center_bounds(Curve *cu, float cent[3]) } -void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, const float unit_scale) +void BKE_curve_transform_ex( + Curve *cu, float mat[4][4], + const bool do_keys, const bool do_props, const float unit_scale) { Nurb *nu; BPoint *bp; @@ -4456,7 +4458,9 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); - bezt->radius *= unit_scale; + if (do_props) { + bezt->radius *= unit_scale; + } } BKE_nurb_handles_calc(nu); } @@ -4464,7 +4468,9 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons i = nu->pntsu * nu->pntsv; for (bp = nu->bp; i--; bp++) { mul_m4_v3(mat, bp->vec); - bp->radius *= unit_scale; + if (do_props) { + bp->radius *= unit_scale; + } } } } @@ -4480,10 +4486,12 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons } } -void BKE_curve_transform(Curve *cu, float mat[4][4], const bool do_keys) +void BKE_curve_transform( + Curve *cu, float mat[4][4], + const bool do_keys, const bool do_props) { float unit_scale = mat4_to_scale(mat); - BKE_curve_transform_ex(cu, mat, do_keys, unit_scale); + BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale); } void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys) diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 930e28ab7fb..dfc49c996b1 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -473,7 +473,7 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3]) return false; } -void BKE_mball_transform(MetaBall *mb, float mat[4][4]) +void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props) { MetaElem *me; float quat[4]; @@ -485,14 +485,17 @@ void BKE_mball_transform(MetaBall *mb, float mat[4][4]) for (me = mb->elems.first; me; me = me->next) { mul_m4_v3(mat, &me->x); mul_qt_qtqt(me->quat, quat, me->quat); - me->rad *= scale; - /* hrmf, probably elems shouldn't be - * treating scale differently - campbell */ - if (!MB_TYPE_SIZE_SQUARED(me->type)) { - mul_v3_fl(&me->expx, scale); - } - else { - mul_v3_fl(&me->expx, scale_sqrt); + + if (do_props) { + me->rad *= scale; + /* hrmf, probably elems shouldn't be + * treating scale differently - campbell */ + if (!MB_TYPE_SIZE_SQUARED(me->type)) { + mul_v3_fl(&me->expx, scale); + } + else { + mul_v3_fl(&me->expx, scale_sqrt); + } } } } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 47e73f9b777..67d5a038c78 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -66,7 +66,7 @@ /* ************************** Object Tools Exports ******************************* */ /* NOTE: these functions are exported to the Object module to be called from the tools there */ -void ED_armature_apply_transform(Object *ob, float mat[4][4]) +void ED_armature_apply_transform(Object *ob, float mat[4][4], const bool do_props) { bArmature *arm = ob->data; @@ -74,14 +74,14 @@ void ED_armature_apply_transform(Object *ob, float mat[4][4]) ED_armature_to_edit(arm); /* Transform the bones */ - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); /* Turn the list into an armature */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); } -void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]) +void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props) { EditBone *ebone; float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */ @@ -106,27 +106,29 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]) /* apply the transformed roll back */ mat3_to_vec_roll(tmat, NULL, &ebone->roll); - ebone->rad_head *= scale; - ebone->rad_tail *= scale; - ebone->dist *= scale; - - /* we could be smarter and scale by the matrix along the x & z axis */ - ebone->xwidth *= scale; - ebone->zwidth *= scale; + if (do_props) { + ebone->rad_head *= scale; + ebone->rad_tail *= scale; + ebone->dist *= scale; + + /* we could be smarter and scale by the matrix along the x & z axis */ + ebone->xwidth *= scale; + ebone->zwidth *= scale; + } } } -void ED_armature_transform(struct bArmature *arm, float mat[4][4]) +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) { if (arm->edbo) { - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); } else { /* Put the armature into editmode */ ED_armature_to_edit(arm); /* Transform the bones */ - ED_armature_transform_bones(arm, mat); + ED_armature_transform_bones(arm, mat, do_props); /* Go back to object mode*/ ED_armature_from_edit(arm); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 6b8943421bd..9130336228d 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -158,9 +158,9 @@ void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]); void transform_armature_mirror_update(struct Object *obedit); void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around); -void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]); -void ED_armature_apply_transform(struct Object *ob, float mat[4][4]); -void ED_armature_transform(struct bArmature *arm, float mat[4][4]); +void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props); +void ED_armature_apply_transform(struct Object *ob, float mat[4][4], const bool do_props); +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props); #define ARM_GROUPS_NAME 1 #define ARM_GROUPS_ENVELOPE 2 diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 47a3f79b0b4..ccbfc3a4f29 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -414,7 +414,10 @@ static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob) } } -static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale) +static int apply_objects_internal( + bContext *C, ReportList *reports, + bool apply_loc, bool apply_rot, bool apply_scale, + bool do_props) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -531,7 +534,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { - ED_armature_apply_transform(ob, mat); + ED_armature_apply_transform(ob, mat, do_props); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; @@ -540,12 +543,12 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; - BKE_mball_transform(mb, mat); + BKE_mball_transform(mb, mat, do_props); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; scale = mat3_to_scale(rsmat); - BKE_curve_transform_ex(cu, mat, true, scale); + BKE_curve_transform_ex(cu, mat, true, do_props, scale); } else if (ob->type == OB_FONT) { Curve *cu = ob->data; @@ -561,7 +564,9 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l tb->h *= scale; } - cu->fsize *= scale; + if (do_props) { + cu->fsize *= scale; + } } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); @@ -677,9 +682,10 @@ static int object_transform_apply_exec(bContext *C, wmOperator *op) const bool loc = RNA_boolean_get(op->ptr, "location"); const bool rot = RNA_boolean_get(op->ptr, "rotation"); const bool sca = RNA_boolean_get(op->ptr, "scale"); + const bool do_props = RNA_boolean_get(op->ptr, "properties"); if (loc || rot || sca) { - return apply_objects_internal(C, op->reports, loc, rot, sca); + return apply_objects_internal(C, op->reports, loc, rot, sca, do_props); } else { /* allow for redo */ @@ -704,6 +710,8 @@ void OBJECT_OT_transform_apply(wmOperatorType *ot) RNA_def_boolean(ot->srna, "location", 0, "Location", ""); RNA_def_boolean(ot->srna, "rotation", 0, "Rotation", ""); RNA_def_boolean(ot->srna, "scale", 0, "Scale", ""); + RNA_def_boolean(ot->srna, "properties", true, "Apply Properties", + "Modify properties such as curve vertex radius, font size and bone envelope"); } /********************* Set Object Center ************************/ diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 891f5c43ca6..ec700eb00de 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -480,7 +480,7 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr) static void rna_Armature_transform(struct bArmature *arm, float *mat) { - ED_armature_transform(arm, (float (*)[4])mat); + ED_armature_transform(arm, (float (*)[4])mat, true); } #else diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c index b4b3aa84ec5..be6808567bb 100644 --- a/source/blender/makesrna/intern/rna_curve_api.c +++ b/source/blender/makesrna/intern/rna_curve_api.c @@ -45,7 +45,7 @@ #ifdef RNA_RUNTIME static void rna_Curve_transform(Curve *cu, float *mat, int shape_keys) { - BKE_curve_transform(cu, (float (*)[4])mat, shape_keys); + BKE_curve_transform(cu, (float (*)[4])mat, shape_keys, true); DAG_id_tag_update(&cu->id, 0); } diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c index 3d8f375fd88..4c3fa787b94 100644 --- a/source/blender/makesrna/intern/rna_meta_api.c +++ b/source/blender/makesrna/intern/rna_meta_api.c @@ -45,7 +45,7 @@ #ifdef RNA_RUNTIME static void rna_Meta_transform(struct MetaBall *mb, float *mat) { - BKE_mball_transform(mb, (float (*)[4])mat); + BKE_mball_transform(mb, (float (*)[4])mat, true); DAG_id_tag_update(&mb->id, 0); } diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 7ee0e75b2f7..cf6f1e25f03 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -355,7 +355,7 @@ int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struc void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE void WM_main_add_notifier(unsigned int type, void *reference) RET_NONE void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep) RET_NONE -void ED_armature_transform(struct bArmature *arm, float mat[4][4]) RET_NONE +void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) RET_NONE struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op) RET_NULL struct wmTimer *WM_event_add_timer(struct wmWindowManager *wm, struct wmWindow *win, int event_type, double timestep) RET_NULL void WM_event_remove_timer(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer) RET_NONE From b2392afc5036047ccb4ade87c0d133568e9d4ff2 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Fri, 11 Aug 2017 09:13:27 -0400 Subject: [PATCH 12/14] Fix bevel clamping bugs T51247 and T50819. Old bevel 'Clamp overlap' code was very naive: just limit amount to half edge length. This uses more accurate (but not perfect) calculations for the max amount before (many) geometry collisions happen. This is not a backward compatible change - meshes that have modifiers with 'Clamp overlap' will likely have larger allowed bevel widths now. But that can be fixed by turning off clamp overlap and setting the amount to the desired value. --- source/blender/bmesh/tools/bmesh_bevel.c | 233 +++++++++++++++++++---- 1 file changed, 194 insertions(+), 39 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 92b65b94fb8..51a0fa4b2cc 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -4531,53 +4531,198 @@ static void set_profile_spacing(BevelParams *bp) } /* - * Calculate and return an offset that is the lesser of the current + * Assume we have a situation like: + * + * a d + * \ / + * A \ / C + * \ th1 th2/ + * b---------c + * B + * + * where edges are A, B, and C, + * following a face around vertices a, b, c, d; + * th1 is angle abc and th2 is angle bcd; + * and the argument EdgeHalf eb is B, going from b to c. + * In general case, edge offset specs for A, B, C have + * the form ka*t, kb*t, kc*t where ka, kb, kc are some factors + * (may be 0) and t is the current bp->offset. + * We want to calculate t at which the clone of B parallel + * to it collapses. This can be calculated using trig. + * Another case of geometry collision that can happen is + * When B slides along A because A is unbeveled. + * Then it might collide with a. Similarly for B sliding along C. + */ +static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb) +{ + EdgeHalf *ea, *ec, *ebother; + BevVert *bvc; + BMLoop *lb; + BMVert *va, *vb, *vc, *vd; + float ka, kb, kc, g, h, t, den, no_collide_offset, th1, th2, sin1, sin2, tan1, tan2, limit; + + limit = no_collide_offset = bp->offset + 1e6; + if (bp->offset == 0.0f) + return no_collide_offset; + kb = eb->offset_l_spec; + ea = eb->next; /* note: this is in direction b --> a */ + ka = ea->offset_r_spec; + if (eb->is_rev) { + vc = eb->e->v1; + vb = eb->e->v2; + } + else { + vb = eb->e->v1; + vc = eb->e->v2; + } + va = ea->is_rev ? ea->e->v1 : ea->e->v2; + bvc = NULL; + ebother = find_other_end_edge_half(bp, eb, &bvc); + if (ebother != NULL) { + ec = ebother->prev; /* note: this is in direction c --> d*/ + vc = bvc->v; + kc = ec->offset_l_spec; + vd = ec->is_rev ? ec->e->v1 : ec->e->v2; + } + else { + /* No bevvert for w, so C can't be beveled */ + kc = 0.0f; + ec = NULL; + /* Find an edge from c that has same face */ + lb = BM_face_edge_share_loop(eb->fnext, eb->e); + if (!lb) { + return no_collide_offset; + } + if (lb->next->v == vc) + vd = lb->next->next->v; + else if (lb->v == vc) + vd = lb->prev->v; + else { + return no_collide_offset; + } + } + if (ea->e == eb->e || (ec && ec->e == eb->e)) + return no_collide_offset; + ka = ka / bp->offset; + kb = kb / bp->offset; + kc = kc / bp->offset; + th1 = angle_v3v3v3(va->co, vb->co, vc->co); + th2 = angle_v3v3v3(vb->co, vc->co, vd->co); + + /* First calculate offset at which edge B collapses, which happens + * when advancing clones of A, B, C all meet at a point. + * This only happens if at least two of those three edges have non-zero k's */ + sin1 = sinf(th1); + sin2 = sinf(th2); + if ((ka > 0.0f) + (kb > 0.0f) + (kc > 0.0f) >= 2) { + tan1 = tanf(th1); + tan2 = tanf(th2); + g = tan1 * tan2; + h = sin1 * sin2; + den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2); + if (den != 0.0f) { + t = BM_edge_calc_length(eb->e); + t *= g * h / den; + if (t >= 0.0f) + limit = t; + } + } + + /* Now check edge slide cases */ + if (kb > 0.0f && ka == 0.0f /*&& bvb->selcount == 1 && bvb->edgecount > 2*/) { + t = BM_edge_calc_length(ea->e); + t *= sin1 / kb; + if (t >= 0.0f && t < limit) + limit = t; + } + if (kb > 0.0f && kc == 0.0f /* && bvc && ec && bvc->selcount == 1 && bvc->edgecount > 2 */) { + t = BM_edge_calc_length(ec->e); + t *= sin2 / kb; + if (t >= 0.0f && t < limit) + limit = t; + } + return limit; +} + +/* + * We have an edge A between vertices a and b, + * where EdgeHalf ea is the half of A that starts at a. + * For vertex-only bevels, the new vertices slide from a at a rate ka*t + * and from b at a rate kb*t. + * We want to calculate the t at which the two meet. + */ +static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea) +{ + float limit, ka, kb, no_collide_offset, la, kab; + EdgeHalf *eb; + + limit = no_collide_offset = bp->offset + 1e6; + if (bp->offset == 0.0f) + return no_collide_offset; + ka = ea->offset_l_spec / bp->offset; + eb = find_other_end_edge_half(bp, ea, NULL); + kb = eb ? eb->offset_l_spec / bp->offset : 0.0f; + kab = ka + kb; + la = BM_edge_calc_length(ea->e); + if (kab <= 0.0f) + return no_collide_offset; + limit = la / kab; + return limit; +} + +/* + * Calculate an offset that is the lesser of the current * bp.offset and the maximum possible offset before geometry * collisions happen. - * Currently this is a quick and dirty estimate of the max - * possible: half the minimum edge length of any vertex involved - * in a bevel. This is usually conservative. - * The correct calculation is quite complicated. - * TODO: implement this correctly. + * If the offset changes as a result of this, adjust the + * current edge offset specs to reflect this clamping, + * and store the new offset in bp.offset. */ -static float bevel_limit_offset(BMesh *bm, BevelParams *bp) +static void bevel_limit_offset(BevelParams *bp) { - BMVert *v; - BMEdge *e; - BMIter v_iter, e_iter; - float limited_offset, half_elen; - bool vbeveled; + BevVert *bv; + EdgeHalf *eh; + GHashIterator giter; + float limited_offset, offset_factor, collision_offset; + int i; limited_offset = bp->offset; - if (bp->offset_type == BEVEL_AMT_PERCENT) { - if (limited_offset > 50.0f) - limited_offset = 50.0f; - return limited_offset; - } - BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + for (i = 0; i < bv->edgecount; i++) { + eh = &bv->edges[i]; if (bp->vertex_only) { - vbeveled = true; + collision_offset = vertex_collide_offset(bp, eh); + if (collision_offset < limited_offset) + limited_offset = collision_offset; } else { - vbeveled = false; - BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) { - vbeveled = true; - break; - } - } - } - if (vbeveled) { - BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) { - half_elen = 0.5f * BM_edge_calc_length(e); - if (half_elen < limited_offset) - limited_offset = half_elen; - } + collision_offset = geometry_collide_offset(bp, eh); + if (collision_offset < limited_offset) + limited_offset = collision_offset; } } } - return limited_offset; + + if (limited_offset < bp->offset) { + /* All current offset specs have some number times bp->offset, + * so we can just multiply them all by the reduction factor + * of the offset to have the effect of recalculating the specs + * with the new limited_offset. + */ + offset_factor = limited_offset / bp->offset; + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + for (i = 0; i < bv->edgecount; i++) { + eh = &bv->edges[i]; + eh->offset_l_spec *= offset_factor; + eh->offset_r_spec *= offset_factor; + eh->offset_l *= offset_factor; + eh->offset_r *= offset_factor; + } + } + bp->offset = limited_offset; + } } /** @@ -4604,6 +4749,7 @@ void BM_mesh_bevel( BMEdge *e; BevVert *bv; BevelParams bp = {NULL}; + GHashIterator giter; bp.offset = offset; bp.offset_type = offset_type; @@ -4627,24 +4773,33 @@ void BM_mesh_bevel( BLI_memarena_use_calloc(bp.mem_arena); set_profile_spacing(&bp); - if (limit_offset) - bp.offset = bevel_limit_offset(bm, &bp); - /* Analyze input vertices, sorting edges and assigning initial new vertex positions */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { bv = bevel_vert_construct(bm, &bp, v); - if (bv) + if (!limit_offset && bv) build_boundary(&bp, bv, true); } } + /* Perhaps clamp offset to avoid geometry colliisions */ + if (limit_offset) { + bevel_limit_offset(&bp); + + /* Assign initial new vertex positions */ + GHASH_ITER(giter, bp.vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + build_boundary(&bp, bv, true); + } + } + /* Perhaps do a pass to try to even out widths */ if (!bp.vertex_only) { adjust_offsets(&bp); } /* Build the meshes around vertices, now that positions are final */ + /* Note: could use GHASH_ITER over bp.vert_hash when backward compatibility no longer matters */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { bv = find_bevvert(&bp, v); From b6fda7fa43d619f2978e0b1e8d874642935a0a67 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 12 Aug 2017 01:40:28 +1200 Subject: [PATCH 13/14] Fix T52327: Entering/Exiting NLA Tweakmode disables Scene -> Only Keyframes from Selected Channels The tweakmode flag and the selected-channels flag accidentally used the same value, due to confusion over where these flags were supposed to be set. The selected-channels flag has now been moved to use a different value, so that there shouldn't be any further conflicts. To be ported to 2.79. --- source/blender/makesdna/DNA_scene_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index c2711c465e1..cc1991cb2db 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1750,8 +1750,7 @@ typedef struct Scene { /* use preview range */ #define SCER_PRV_RANGE (1<<0) #define SCER_LOCK_FRAME_SELECTION (1<<1) - /* timeline/keyframe jumping - only selected items (on by default) */ -#define SCE_KEYS_NO_SELONLY (1<<2) + /* show/use subframes (for checking motion blur) */ #define SCER_SHOW_SUBFRAME (1<<3) /* mode (int now) */ @@ -2085,6 +2084,7 @@ typedef enum eVGroupSelect { #define SCE_DS_COLLAPSED (1<<1) #define SCE_NLA_EDIT_ON (1<<2) #define SCE_FRAME_DROP (1<<3) +#define SCE_KEYS_NO_SELONLY (1<<4) /* return flag BKE_scene_base_iter_next functions */ From e6da7bb75c8eff13185a56a144dce920b3886ecb Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 12 Aug 2017 01:52:51 +1200 Subject: [PATCH 14/14] Fix T52346: Alt-I (Delete Keyframes) on a NlaStrip's Extrapolate property would crash --- source/blender/editors/animation/keyframing.c | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index e11d8bb1bba..540886196fe 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1786,7 +1786,9 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); - success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0); + if (fcu) { + success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0); + } } else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) { /* Driven property - Find driver */ @@ -1891,27 +1893,27 @@ static int delete_key_button_exec(bContext *C, wmOperator *op) NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0); - BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */ - - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(op->reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", - strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); - } - else { - /* remove the keyframe directly - * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, - * and delete_keyframe() expects the FCurve to be part of an action - */ - bool found = false; - int i; - - /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); - if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards) */ - delete_fcurve_key(fcu, i, 1); - success = true; + if (fcu) { + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(op->reports, RPT_WARNING, + "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", + strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); + } + else { + /* remove the keyframe directly + * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, + * and delete_keyframe() expects the FCurve to be part of an action + */ + bool found = false; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + success = true; + } } } }