From 475b7f5a2cadd2e7ec71c8ba9fa5dad97f4c2afa Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 23 Jun 2016 11:23:31 +1000 Subject: BLI_array_utils: add BLI_array_rfindindex Array search from back to front. --- source/blender/blenlib/BLI_array_utils.h | 4 ++++ source/blender/blenlib/intern/array_utils.c | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h index 5ef8421c003..a46c87cec40 100644 --- a/source/blender/blenlib/BLI_array_utils.h +++ b/source/blender/blenlib/BLI_array_utils.h @@ -48,6 +48,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid #define BLI_array_findindex(arr, arr_len, p) \ _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) +int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); +#define BLI_array_rfindindex(arr, arr_len, p) \ + _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p) + void _bli_array_binary_and( void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride); diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c index 9c91da4abee..32f0111babd 100644 --- a/source/blender/blenlib/intern/array_utils.c +++ b/source/blender/blenlib/intern/array_utils.c @@ -134,8 +134,22 @@ void _bli_array_permute( int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) { const char *arr_step = (const char *)arr; - unsigned int i; - for (i = 0; i < arr_len; i++, arr_step += arr_stride) { + for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) { + if (memcmp(arr_step, p, arr_stride) == 0) { + return (int)i; + } + } + return -1; +} + +/** + * A version of #BLI_array_findindex that searches from the end of the list. + */ +int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) +{ + const char *arr_step = (const char *)arr + (arr_stride * arr_len); + for (unsigned int i = arr_len; i-- != 0; ) { + arr_step -= arr_stride; if (memcmp(arr_step, p, arr_stride) == 0) { return (int)i; } -- cgit v1.2.3 From fad0c336e44bdb4910c6dbeb8e2973f3695689f1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 23 Jun 2016 11:52:22 +1000 Subject: RNA: Expose hook inverse matrix Needed so scripts don't need to use operators to adjust hook modifiers. --- source/blender/makesrna/intern/rna_modifier.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 5a2113f3f95..a7c9f29e7d3 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1826,6 +1826,12 @@ static void rna_def_modifier_hook(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hook Center", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "parentinv"); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target"); + RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Modifier_update"); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); -- cgit v1.2.3 From a8898d310544a3781817c2288f39286bbe4ccf94 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 23 Jun 2016 12:26:26 +1000 Subject: Correct assert --- source/blender/bmesh/tools/bmesh_intersect.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'source/blender') diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 9d1f7fa45d2..7496af1d64c 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -685,8 +685,8 @@ static void bm_isect_tri_tri( continue; if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1); - BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1); + BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), &fv_a[i_a]) == -1); + BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), &fv_a[i_a]) == -1); STACK_PUSH(iv_ls_a, fv_a[i_a]); STACK_PUSH(iv_ls_b, fv_a[i_a]); @@ -715,8 +715,8 @@ static void bm_isect_tri_tri( if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1); + BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), &fv_b[i_b]) == -1); + BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), &fv_b[i_b]) == -1); STACK_PUSH(iv_ls_a, fv_b[i_b]); STACK_PUSH(iv_ls_b, fv_b[i_b]); @@ -753,8 +753,8 @@ static void bm_isect_tri_tri( continue; iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); + BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), &iv) == -1); + BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), &iv) == -1); STACK_PUSH(iv_ls_a, iv); STACK_PUSH(iv_ls_b, iv); #ifdef USE_DUMP @@ -771,8 +771,8 @@ static void bm_isect_tri_tri( continue; iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); + BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), &iv) == -1); + BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), &iv) == -1); STACK_PUSH(iv_ls_a, iv); STACK_PUSH(iv_ls_b, iv); #ifdef USE_DUMP -- cgit v1.2.3 From 219a8d046a78b55d0803bbf1d87d19d6ae948807 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 23 Jun 2016 18:43:36 +1000 Subject: Use hard min/max for view clipping In rare cases its useful to have far clip below 1. --- source/blender/makesrna/intern/rna_camera.c | 6 ++++-- source/blender/makesrna/intern/rna_space.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 678b0ac8f1f..492430fbda6 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -257,13 +257,15 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipsta"); - RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipend"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 2c9ebdd27fe..4273c29aed8 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2447,14 +2447,16 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "near"); - RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_float_default(prop, 0.1f); RNA_def_property_ui_text(prop, "Clip Start", "3D View near clipping distance (perspective view only)"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "far"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_float_default(prop, 1000.0f); RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); -- cgit v1.2.3 From 097611a92a48e5dc45cd9b7d2f5d2c4edb364207 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 23 Jun 2016 13:09:32 +0200 Subject: Fix T48710: 'velocity' particle settings were incorrectly using 'speed' in their tooltips. Not the same thing, velocity is a vector conveying both speed *and* direction... --- source/blender/makesrna/intern/rna_particle.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 1f9418f8353..a52473b95f2 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -2635,35 +2635,35 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "normfac"); /*optional if prop names are the same */ RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_range(prop, 0, 100, 1, 3); - RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "object_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "obfac"); RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "factor_random", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "randfac"); /*optional if prop names are the same */ RNA_def_property_range(prop, 0.0f, 200.0f); RNA_def_property_ui_range(prop, 0, 100, 1, 3); - RNA_def_property_ui_text(prop, "Random", "Give the starting speed a random variation"); + RNA_def_property_ui_text(prop, "Random", "Give the starting velocity a random variation"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "particle_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "partfac"); RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "tangent_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "tanfac"); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_range(prop, -100, 100, 1, 2); - RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "tangent_phase", PROP_FLOAT, PROP_NONE); @@ -2677,7 +2677,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_range(prop, -10.0f, 10.0f); RNA_def_property_ui_text(prop, "Reactor", "Let the vector away from the target particle's location give the particle " - "a starting speed"); + "a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "object_align_factor", PROP_FLOAT, PROP_VELOCITY); @@ -2686,7 +2686,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -100, 100, 1, 3); RNA_def_property_ui_text(prop, "Object Aligned", - "Let the emitter object orientation give the particle a starting speed"); + "Let the emitter object orientation give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "angular_velocity_factor", PROP_FLOAT, PROP_NONE); -- cgit v1.2.3 From 57744df38fef172edf7781f1e1bb48319f5ef066 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 23 Jun 2016 22:19:09 +1000 Subject: Correct recent change to edge-net Need account for cases where vertex connects a single edge. --- .../blender/bmesh/intern/bmesh_polygon_edgenet.c | 50 ++++++++++++---------- 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'source/blender') diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index c142dcae514..5ef19b58c9d 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -309,36 +309,40 @@ walk_nofork: BMEdge *e_next, *e_first; e_first = v->e; e_next = BM_DISK_EDGE_NEXT(e_first, v); /* always skip this verts edge */ - do { - BLI_assert(v->e != e_next); - if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && - (bm_edge_flagged_radial_count(e_next) < 2)) - { - BMVert *v_next; - v_next = BM_edge_other_vert(e_next, v); + /* in rare cases there may be edges with a single connecting vertex */ + if (e_next != e_first) { + do { + if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && + (bm_edge_flagged_radial_count(e_next) < 2)) + { + BMVert *v_next; + + v_next = BM_edge_other_vert(e_next, v); + BLI_assert(v->e != e_next); #ifdef DEBUG_PRINT - /* indent and print */ - { - BMVert *_v = v; - do { - printf(" "); - } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); - printf("vert %d -> %d (add=%d)\n", - BM_elem_index_get(v), BM_elem_index_get(v_next), - BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); - } + /* indent and print */ + { + BMVert *_v = v; + do { + printf(" "); + } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); + printf("vert %d -> %d (add=%d)\n", + BM_elem_index_get(v), BM_elem_index_get(v_next), + BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); + } #endif - if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { - eo = STACK_PUSH_RET_PTR(edge_order); - eo->v = v_next; + if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { + eo = STACK_PUSH_RET_PTR(edge_order); + eo->v = v_next; - v_next->e = e_next; + v_next->e = e_next; + } } - } - } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first); + } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first); + } #ifdef USE_FASTPATH_NOFORK if (STACK_SIZE(edge_order) == 1) { -- cgit v1.2.3 From d9a01a1d04f87e46fadbee268cdea2dbf14993fc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 23 Jun 2016 21:44:22 +1000 Subject: Fix T48707: Edit-mesh intersect crash In rare cases intersect would attempt to add edges with the same vertex twice from edge-vert / edge-edge intersections. Solve by checking for duplicates when creating vertex-array for these types of intersections (always under 3x comparisons, so not much overhead). --- source/blender/bmesh/tools/bmesh_intersect.c | 80 +++++++++++++++++++--------- 1 file changed, 56 insertions(+), 24 deletions(-) (limited to 'source/blender') diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 7496af1d64c..bd6a68faabb 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -87,6 +87,18 @@ // #define USE_DUMP +/* use only for small arrays */ +BLI_INLINE bool array_contains_pointer(const void **arr, unsigned int arr_len, const void *item) +{ + BLI_assert(arr_len < 3); + for (unsigned int i = 0; i < arr_len; i++) { + if (arr[i] == item) { + return true; + } + } + return false; +} + static void tri_v3_scale( float v1[3], float v2[3], float v3[3], const float t) @@ -535,6 +547,7 @@ static void bm_isect_tri_tri( const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)}; float f_a_nor[3]; float f_b_nor[3]; + /* track vertices which have been added to 'iv_ls_a' & 'iv_ls_b' */ int a_mask = 0; int b_mask = 0; unsigned int i; @@ -556,6 +569,24 @@ static void bm_isect_tri_tri( STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a)); STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b)); + /* don't test, but we must be sure not to add doubles (assert instead). */ +#ifndef NDEBUG +# define STACK_PUSH_NOTEST(arr, ele) \ + { \ + BLI_assert(BLI_array_findindex(arr, STACK_SIZE(arr), &(ele)) == -1); \ + STACK_PUSH(arr, ele); \ + } ((void)0) +#else +# define STACK_PUSH_NOTEST STACK_PUSH +#endif + + /* warning, this seems like it might be inefficent, + * however there will be <3 items in this case. */ +# define STACK_PUSH_TEST(arr, ele, arr_offset) \ + if (!array_contains_pointer((const void **)(&(arr)[arr_offset]), STACK_SIZE(arr) - (arr_offset), (void *)ele)) { \ + STACK_PUSH(arr, ele); \ + } ((void)0) + /* vert-vert * --------- */ { @@ -568,7 +599,7 @@ static void bm_isect_tri_tri( for (i_b = 0; i_b < 3; i_b++) { if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { if (!((1 << i_a) & a_mask)) { - STACK_PUSH(iv_ls_a, fv_a[i_a]); + STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]); a_mask |= (1 << i_a); #ifdef USE_DUMP printf(" ('VERT-VERT-A') %d, %d),\n", @@ -576,7 +607,7 @@ static void bm_isect_tri_tri( #endif } if (!((1 << i_b) & b_mask)) { - STACK_PUSH(iv_ls_b, fv_b[i_b]); + STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]); b_mask |= (1 << i_b); #ifdef USE_DUMP printf(" ('VERT-VERT-B') %d, %d),\n", @@ -606,8 +637,8 @@ static void bm_isect_tri_tri( interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac); if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { BMEdge *e; - STACK_PUSH(iv_ls_b, fv_a[i_a]); - // STACK_PUSH(iv_ls_a, fv_a[i_a]); + STACK_PUSH_NOTEST(iv_ls_b, fv_a[i_a]); + // STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]); a_mask |= (1 << i_a); e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]); #ifdef USE_DUMP @@ -644,8 +675,8 @@ static void bm_isect_tri_tri( interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac); if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { BMEdge *e; - STACK_PUSH(iv_ls_a, fv_b[i_b]); - // STACK_PUSH(iv_ls_b, fv_b[i_b]); + STACK_PUSH_NOTEST(iv_ls_a, fv_b[i_b]); + // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]); b_mask |= (1 << i_b); e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]); #ifdef USE_DUMP @@ -685,11 +716,8 @@ static void bm_isect_tri_tri( continue; if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), &fv_a[i_a]) == -1); - BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), &fv_a[i_a]) == -1); - - STACK_PUSH(iv_ls_a, fv_a[i_a]); - STACK_PUSH(iv_ls_b, fv_a[i_a]); + STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]); + STACK_PUSH_NOTEST(iv_ls_b, fv_a[i_a]); a_mask |= (1 << i_a); #ifdef USE_DUMP printf(" 'VERT TRI-A',\n"); @@ -715,11 +743,8 @@ static void bm_isect_tri_tri( if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), &fv_b[i_b]) == -1); - BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), &fv_b[i_b]) == -1); - - STACK_PUSH(iv_ls_a, fv_b[i_b]); - STACK_PUSH(iv_ls_b, fv_b[i_b]); + STACK_PUSH_NOTEST(iv_ls_a, fv_b[i_b]); + STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]); b_mask |= (1 << i_b); #ifdef USE_DUMP printf(" 'VERT TRI-B',\n"); @@ -744,6 +769,17 @@ static void bm_isect_tri_tri( /* edge-tri & edge-edge * -------------------- */ { + /** + * Note that its possible to add the same vertex multiple times + * with near degenerate faces (or a large epsilon). + * + * For this reason we have #STACK_PUSH_TEST macro which only adds vertices that aren't already added. + * Since we know none of the vertices from #bm_isect_edge_tri, the check can be offset. + */ + + const unsigned int iv_ls_a_offset = STACK_SIZE(iv_ls_a); + const unsigned int iv_ls_b_offset = STACK_SIZE(iv_ls_b); + unsigned int i_e0; for (i_e0 = 0; i_e0 < 3; i_e0++) { unsigned int i_e1 = (i_e0 + 1) % 3; @@ -753,10 +789,8 @@ static void bm_isect_tri_tri( continue; iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), &iv) == -1); - BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), &iv) == -1); - STACK_PUSH(iv_ls_a, iv); - STACK_PUSH(iv_ls_b, iv); + STACK_PUSH_TEST(iv_ls_a, iv, iv_ls_a_offset); + STACK_PUSH_TEST(iv_ls_b, iv, iv_ls_b_offset); #ifdef USE_DUMP printf(" ('EDGE-TRI-A', %d),\n", side); #endif @@ -771,10 +805,8 @@ static void bm_isect_tri_tri( continue; iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), &iv) == -1); - BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), &iv) == -1); - STACK_PUSH(iv_ls_a, iv); - STACK_PUSH(iv_ls_b, iv); + STACK_PUSH_TEST(iv_ls_a, iv, iv_ls_a_offset); + STACK_PUSH_TEST(iv_ls_b, iv, iv_ls_b_offset); #ifdef USE_DUMP printf(" ('EDGE-TRI-B', %d),\n", side); #endif -- cgit v1.2.3 From 37560e77e8919a47f6607af5dfb356a8fa70a6f8 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 23 Jun 2016 16:43:12 +0200 Subject: Fix T48689: Transform proportional size was not seriously clamped. Now use same, reasonable min/max values, to avoid getting inf or zero values when using shortcuts during transform operation... --- source/blender/editors/transform/transform.c | 15 ++++++++++++--- source/blender/editors/transform/transform.h | 4 ++++ source/blender/editors/transform/transform_ops.c | 3 ++- 3 files changed, 18 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 74ed2014f55..7671154526a 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1202,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) if (t->flag & T_PROP_EDIT) { float fac = 1.0f + 0.005f *(event->y - event->prevy); t->prop_size *= fac; - if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) - t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { + t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN); + } + else { + t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN); + } calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -1212,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_PROPSIZE_UP: if (t->flag & T_PROP_EDIT) { t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; - if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + } + else { + t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX); + } calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -1222,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_PROPSIZE_DOWN: if (t->flag & T_PROP_EDIT) { t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; + t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN); calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 0e0d085bf6f..50168e78dda 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -592,6 +592,10 @@ typedef struct TransInfo { #define POINT_INIT 4 #define MULTI_POINTS 8 +/* Hard min/max for proportional size. */ +#define T_PROP_SIZE_MIN 1e-6f +#define T_PROP_SIZE_MAX 1e12f + bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode); void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op); int transformEvent(TransInfo *t, const struct wmEvent *event); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 2fb92d73515..6e399d9fde3 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0, "Proportional Editing Falloff", "Falloff type for proportional editing mode"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ - RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100); + RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX, + "Proportional Size", "", 0.001f, 100.0f); } if (flags & P_SNAP) { -- cgit v1.2.3 From ec7603d6f115bfae53b7b0c887fd0b46a82a16d6 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 18 Jun 2016 12:58:26 +1200 Subject: GPencil: Added a new version of the "delete active frame" operator which deletes on all editable layers This new operator will delete any GP frame it finds on the current frame, regardless of whether it's on the active layer or not. It will only remove the frames if the layer is editable, but otherwise, it will just go for it. The existing operator is great for use in the panel (where it only applies to the active frame), but it was not so good for all the other places where tools can be invoked (e.g. D-X, or Delete) as you're typically thinking about the whole scene more holisticaly than just caring about a particular layer. --- source/blender/editors/gpencil/gpencil_edit.c | 60 ++++++++++++++++++++++++- source/blender/editors/gpencil/gpencil_intern.h | 1 + source/blender/editors/gpencil/gpencil_ops.c | 5 ++- 3 files changed, 63 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index bd1697b9a54..ac49a51c716 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) /* identifiers */ ot->name = "Delete Active Frame"; ot->idname = "GPENCIL_OT_active_frame_delete"; - ot->description = "Delete the active frame for the active Grease Pencil datablock"; + ot->description = "Delete the active frame for the active Grease Pencil Layer"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) ot->poll = gp_actframe_delete_poll; } +/* **************** Delete All Active Frames ****************** */ + +static int gp_actframe_delete_all_poll(bContext *C) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + + /* 1) There must be grease pencil data + * 2) Hopefully some of the layers have stuff we can use + */ + return (gpd && gpd->layers.first); +} + +static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + bool success = false; + + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + /* try to get the "active" frame - but only if it actually occurs on this frame */ + bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); + + if (gpf == NULL) + continue; + + /* delete it... */ + gpencil_layer_delframe(gpl, gpf); + + /* we successfully modified something */ + success = true; + } + CTX_DATA_END; + + /* updates */ + if (success) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete"); + return OPERATOR_CANCELLED; + } +} + +void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete All Active Frames"; + ot->idname = "GPENCIL_OT_active_frames_delete_all"; + ot->description = "Delete the active frame(s) of all editable Grease Pencil layers"; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* callbacks */ + ot->exec = gp_actframe_delete_all_exec; + ot->poll = gp_actframe_delete_all_poll; +} + /* ******************* Delete Operator ************************ */ typedef enum eGP_DeleteMode { diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index dd28f6ac531..53fb33eeb9b 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot); void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot); void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot); +void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot); void GPENCIL_OT_convert(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 405b673c42b..65ee1122b56 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) /* Delete Active Frame - For easier video tutorials/review sessions */ /* NOTE: This works even when not in EditMode */ - WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY); } /* ==================== */ @@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0); /* copy + paste */ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); @@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_layer_isolate); WM_operatortype_append(GPENCIL_OT_active_frame_delete); + WM_operatortype_append(GPENCIL_OT_active_frames_delete_all); WM_operatortype_append(GPENCIL_OT_convert); -- cgit v1.2.3 From 58acc184c4d53af53f245505a5952653e75856f3 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 23 Jun 2016 19:36:24 +1200 Subject: Code Cleanup - Circle/Lasso select in the Graph Editor --- source/blender/editors/animation/keyframes_edit.c | 4 +- source/blender/editors/include/ED_keyframes_edit.h | 8 +-- source/blender/editors/space_graph/graph_ops.c | 7 +- source/blender/editors/space_graph/graph_select.c | 84 +++++++++++----------- 4 files changed, 50 insertions(+), 53 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 08a7355694b..cd00b963482 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -542,7 +542,7 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt) * only called from #ok_bezier_region_lasso */ static bool bezier_region_lasso_test( - const struct KeyframeEdit_LassoData *data_lasso, + const KeyframeEdit_LassoData *data_lasso, const float xy[2]) { if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) { @@ -579,7 +579,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) * only called from #ok_bezier_region_circle */ static bool bezier_region_circle_test( - const struct KeyframeEdit_CircleData *data_circle, + const KeyframeEdit_CircleData *data_circle, const float xy[2]) { if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) { diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index fae3e3677a0..ab51298eb6c 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -97,20 +97,20 @@ typedef enum eEditKeyframes_Mirror { } eEditKeyframes_Mirror; /* use with BEZT_OK_REGION_LASSO */ -struct KeyframeEdit_LassoData { +typedef struct KeyframeEdit_LassoData { const rctf *rectf_scaled; const rctf *rectf_view; const int (*mcords)[2]; int mcords_tot; -}; +} KeyframeEdit_LassoData; /* use with BEZT_OK_REGION_CIRCLE */ -struct KeyframeEdit_CircleData { +typedef struct KeyframeEdit_CircleData { const rctf *rectf_scaled; const rctf *rectf_view; float mval[2]; float radius_squared; -}; +} KeyframeEdit_CircleData; /* ************************************************ */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 6b860990c10..478dbd3d9c0 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); RNA_boolean_set(kmi->ptr, "include_handles", false); - + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "axis_range", false); RNA_boolean_set(kmi->ptr, "include_handles", true); kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); RNA_boolean_set(kmi->ptr, "include_handles", true); - + + /* region select */ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "deselect", false); kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "deselect", true); - + WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0); /* column select */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index eb786d872ec..8c058d23cde 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot) * -> ALT-BKEY - depending on which axis of the region was larger... * -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE) * -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE) + * + * The selection backend is also reused for the Lasso and Circle select operators. */ /* Borderselect only selects keyframes now, as overshooting handles often get caught too, @@ -245,12 +247,12 @@ static void borderselect_graphkeys( /* init editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); if (mode == BEZT_OK_REGION_LASSO) { - struct KeyframeEdit_LassoData *data_lasso = data; + KeyframeEdit_LassoData *data_lasso = data; data_lasso->rectf_scaled = &scaled_rectf; ked.data = data_lasso; } else if (mode == BEZT_OK_REGION_CIRCLE) { - struct KeyframeEdit_CircleData *data_circle = data; + KeyframeEdit_CircleData *data_circle = data; data_circle->rectf_scaled = &scaled_rectf; ked.data = data; } @@ -265,27 +267,27 @@ static void borderselect_graphkeys( } else mapping_flag = ANIM_UNITCONV_ONLYKEYS; - + mapping_flag |= ANIM_get_normalization_flags(ac); - + /* loop over data, doing border select */ for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); FCurve *fcu = (FCurve *)ale->key_data; float offset; float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); - + /* apply NLA mapping to all the keyframes, since it's easier than trying to * guess when a callback might use something different */ if (adt) ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0); - + scaled_rectf.xmin = rectf.xmin; scaled_rectf.xmax = rectf.xmax; scaled_rectf.ymin = rectf.ymin / unit_scale - offset; scaled_rectf.ymax = rectf.ymax / unit_scale - offset; - + /* set horizontal range (if applicable) * NOTE: these values are only used for x-range and y-range but not region * (which uses ked.data, i.e. rectf) @@ -406,37 +408,42 @@ void GRAPH_OT_select_border(wmOperatorType *ot) RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria"); } + +/* ------------------- */ + static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; + + KeyframeEdit_LassoData data_lasso; rcti rect; rctf rect_fl; + short selectmode; bool incl_handles; bool extend; - - struct KeyframeEdit_LassoData data_lasso; - + + /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + data_lasso.rectf_view = &rect_fl; data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); if (data_lasso.mcords == NULL) return OPERATOR_CANCELLED; - + /* clear all selection if not extending selection */ extend = RNA_boolean_get(op->ptr, "extend"); if (!extend) deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true); - + if (!RNA_boolean_get(op->ptr, "deselect")) selectmode = SELECT_ADD; else selectmode = SELECT_SUBTRACT; - - if (ac.spacetype == SPACE_IPO) { + + { SpaceIpo *sipo = (SpaceIpo *)ac.sl; if (selectmode == SELECT_ADD) { incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || @@ -446,60 +453,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; } } - else { - incl_handles = false; - } - - + /* get settings from operator */ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); - BLI_rctf_rcti_copy(&rect_fl, &rect); - + /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso); - + MEM_freeN((void *)data_lasso.mcords); - - + /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + return OPERATOR_FINISHED; } - void GRAPH_OT_select_lasso(wmOperatorType *ot) { /* identifiers */ ot->name = "Lasso Select"; ot->description = "Select keyframe points using lasso selection"; ot->idname = "GRAPH_OT_select_lasso"; - + /* api callbacks */ ot->invoke = WM_gesture_lasso_invoke; ot->modal = WM_gesture_lasso_modal; ot->exec = graphkeys_lassoselect_exec; ot->poll = graphop_visible_keyframes_poll; ot->cancel = WM_gesture_lasso_cancel; - + /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } +/* ------------------- */ + static int graph_circle_select_exec(bContext *C, wmOperator *op) { bAnimContext ac; const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); - short selectmode; - bool incl_handles; + const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; + bool incl_handles = false; + + KeyframeEdit_CircleData data; rctf rect_fl; - struct KeyframeEdit_CircleData data; + float x = RNA_int_get(op->ptr, "x"); float y = RNA_int_get(op->ptr, "y"); float radius = RNA_int_get(op->ptr, "radius"); @@ -507,23 +511,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + data.mval[0] = x; data.mval[1] = y; data.radius_squared = radius * radius; data.rectf_view = &rect_fl; - if (gesture_mode == GESTURE_MODAL_SELECT) - selectmode = SELECT_ADD; - else - selectmode = SELECT_SUBTRACT; - rect_fl.xmin = x - radius; rect_fl.xmax = x + radius; rect_fl.ymin = y - radius; rect_fl.ymax = y + radius; - if (ac.spacetype == SPACE_IPO) { + { SpaceIpo *sipo = (SpaceIpo *)ac.sl; if (selectmode == SELECT_ADD) { incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || @@ -533,10 +532,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; } } - else { - incl_handles = false; - } - + /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data); -- cgit v1.2.3 From 7e53f9fb1af850271d92ddc92a50acbc7aafd48f Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 23 Jun 2016 23:16:14 +1200 Subject: Dopesheet: Lasso and Circle Select tools work for selecting keyframes This only works in the Action and Dopesheet modes (which operate on FCurve keyframes). Support for Grease Pencil and Mask Keyframes though is still pending. --- source/blender/editors/animation/keyframes_edit.c | 62 ++++- source/blender/editors/include/ED_keyframes_edit.h | 14 +- .../blender/editors/space_action/action_intern.h | 2 + source/blender/editors/space_action/action_ops.c | 10 + .../blender/editors/space_action/action_select.c | 259 +++++++++++++++++++++ source/blender/editors/space_graph/graph_select.c | 5 +- source/blender/windowmanager/intern/wm_operators.c | 3 +- 7 files changed, 346 insertions(+), 9 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index cd00b963482..f909b39cca3 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -539,7 +539,7 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt) } /** - * only called from #ok_bezier_region_lasso + * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso */ static bool bezier_region_lasso_test( const KeyframeEdit_LassoData *data_lasso, @@ -575,8 +575,35 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) return 0; } +static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt) +{ + /* check for lasso customdata (KeyframeEdit_LassoData) */ + if (ked->data) { + KeyframeEdit_LassoData *data = ked->data; + float pt[2]; + + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } + + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; + + if (bezier_region_lasso_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; +} + /** - * only called from #ok_bezier_region_circle + * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle */ static bool bezier_region_circle_test( const KeyframeEdit_CircleData *data_circle, @@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) return 0; } +static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt) +{ + /* check for circle select customdata (KeyframeEdit_CircleData) */ + if (ked->data) { + KeyframeEdit_CircleData *data = ked->data; + float pt[2]; + + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } + + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; + + if (bezier_region_circle_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; +} + KeyframeEditFunc ANIM_editkeyframes_ok(short mode) { @@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode) return ok_bezier_region_lasso; case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */ return ok_bezier_region_circle; + case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */ + return ok_bezier_channel_lasso; + case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */ + return ok_bezier_channel_circle; default: /* nothing was ok */ return NULL; } diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index ab51298eb6c..0d352ab5ead 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -45,14 +45,21 @@ struct Scene; /* bezt validation */ typedef enum eEditKeyframes_Validate { + /* Frame range */ BEZT_OK_FRAME = 1, BEZT_OK_FRAMERANGE, + /* Selection status */ BEZT_OK_SELECTED, + /* Values (y-val) only */ BEZT_OK_VALUE, BEZT_OK_VALUERANGE, + /* For graph editor keyframes (2D tests) */ BEZT_OK_REGION, BEZT_OK_REGION_LASSO, BEZT_OK_REGION_CIRCLE, + /* Only for keyframes a certain Dopesheet channel */ + BEZT_OK_CHANNEL_LASSO, + BEZT_OK_CHANNEL_CIRCLE, } eEditKeyframes_Validate; /* ------------ */ @@ -98,7 +105,7 @@ typedef enum eEditKeyframes_Mirror { /* use with BEZT_OK_REGION_LASSO */ typedef struct KeyframeEdit_LassoData { - const rctf *rectf_scaled; + rctf *rectf_scaled; const rctf *rectf_view; const int (*mcords)[2]; int mcords_tot; @@ -106,7 +113,7 @@ typedef struct KeyframeEdit_LassoData { /* use with BEZT_OK_REGION_CIRCLE */ typedef struct KeyframeEdit_CircleData { - const rctf *rectf_scaled; + rctf *rectf_scaled; const rctf *rectf_view; float mval[2]; float radius_squared; @@ -157,7 +164,8 @@ typedef struct KeyframeEditData { /* current iteration data */ struct FCurve *fcu; /* F-Curve that is being iterated over */ int curIndex; /* index of current keyframe being iterated over */ - + float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */ + /* flags */ eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */ eKeyframeIterFlags iterflags; /* settings for iteration process */ diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 50e10e7e154..408eb38d386 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s void ACTION_OT_select_all_toggle(struct wmOperatorType *ot); void ACTION_OT_select_border(struct wmOperatorType *ot); +void ACTION_OT_select_lasso(struct wmOperatorType *ot); +void ACTION_OT_select_circle(struct wmOperatorType *ot); void ACTION_OT_select_column(struct wmOperatorType *ot); void ACTION_OT_select_linked(struct wmOperatorType *ot); void ACTION_OT_select_more(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index f69f9944f8a..a261202b690 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -59,6 +59,8 @@ void action_operatortypes(void) WM_operatortype_append(ACTION_OT_clickselect); WM_operatortype_append(ACTION_OT_select_all_toggle); WM_operatortype_append(ACTION_OT_select_border); + WM_operatortype_append(ACTION_OT_select_lasso); + WM_operatortype_append(ACTION_OT_select_circle); WM_operatortype_append(ACTION_OT_select_column); WM_operatortype_append(ACTION_OT_select_linked); WM_operatortype_append(ACTION_OT_select_more); @@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); + /* region select */ + kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); + kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "deselect", true); + + WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0); + /* column select */ RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS); RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index f2813b2a8d3..c9a4922eb0b 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -36,6 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_dlrbTree.h" +#include "BLI_lasso.h" #include "BLI_utildefines.h" #include "DNA_anim_types.h" @@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot) ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); } +/* ******************** Region Select Operators ***************************** */ +/* "Region Select" operators include the Lasso and Circle Select operators. + * These two ended up being lumped together, as it was easier in the + * original Graph Editor implmentation of these to do it this way. + */ + +static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked; + KeyframeEditFunc ok_cb, select_cb; + View2D *v2d = &ac->ar->v2d; + rctf rectf, scaled_rectf; + float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF); + + /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ + UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get beztriple editing/validation funcs */ + select_cb = ANIM_editkeyframes_select(selectmode); + ok_cb = ANIM_editkeyframes_ok(mode); + + /* init editing data */ + memset(&ked, 0, sizeof(KeyframeEditData)); + if (mode == BEZT_OK_CHANNEL_LASSO) { + KeyframeEdit_LassoData *data_lasso = data; + data_lasso->rectf_scaled = &scaled_rectf; + ked.data = data_lasso; + } + else if (mode == BEZT_OK_CHANNEL_CIRCLE) { + KeyframeEdit_CircleData *data_circle = data; + data_circle->rectf_scaled = &scaled_rectf; + ked.data = data; + } + else { + ked.data = &scaled_rectf; + } + + /* loop over data, doing region select */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* get new vertical minimum extent of channel */ + ymin = ymax - ACHANNEL_STEP; + + /* compute midpoint of channel (used for testing if the key is in the region or not) */ + ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF; + + /* if channel is mapped in NLA, apply correction + * - Apply to the bounds being checked, not all the keyframe points, + * to avoid having scaling everything + * - Save result to the scaled_rect, which is all that these operators + * will read from + */ + if (adt) { + ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); + ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); + ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); + } + else { + ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */ + ked.f1 = rectf.xmin; + ked.f2 = rectf.xmax; + } + + /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks + * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these + * with the properly remapped ked.f1/f2 values, when needed + */ + scaled_rectf.xmin = ked.f1; + scaled_rectf.xmax = ked.f2; + scaled_rectf.ymin = ymin; + scaled_rectf.ymax = ymax; + + /* perform vertical suitability check (if applicable) */ + if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || + !((ymax < rectf.ymin) || (ymin > rectf.ymax))) + { + /* loop over data selecting */ + switch (ale->type) { + case ANIMTYPE_GPDATABLOCK: + { + bGPdata *gpd = ale->data; + bGPDlayer *gpl; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + //ED_gplayer_frames_select_border(gpl, rectf.xmin, rectf.xmax, selectmode); + } + break; + } + case ANIMTYPE_GPLAYER: + { + //ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode); + break; + } + case ANIMTYPE_MASKDATABLOCK: + { + Mask *mask = ale->data; + MaskLayer *masklay; + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + //ED_masklayer_frames_select_border(masklay, rectf.xmin, rectf.xmax, selectmode); + } + break; + } + case ANIMTYPE_MASKLAYER: + { + //ED_masklayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode); + break; + } + default: + ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); + break; + } + } + + /* set minimum extent to be the maximum of the next channel */ + ymax = ymin; + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); +} + +/* ----------------------------------- */ + +static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + KeyframeEdit_LassoData data_lasso; + rcti rect; + rctf rect_fl; + + short selectmode; + bool extend; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data_lasso.rectf_view = &rect_fl; + data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); + if (data_lasso.mcords == NULL) + return OPERATOR_CANCELLED; + + /* clear all selection if not extending selection */ + extend = RNA_boolean_get(op->ptr, "extend"); + if (!extend) + deselect_action_keys(&ac, 1, SELECT_SUBTRACT); + + if (!RNA_boolean_get(op->ptr, "deselect")) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + + /* get settings from operator */ + BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_rctf_rcti_copy(&rect_fl, &rect); + + /* apply borderselect action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso); + + MEM_freeN((void *)data_lasso.mcords); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_select_lasso(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Lasso Select"; + ot->description = "Select keyframe points using lasso selection"; + ot->idname = "ACTION_OT_select_lasso"; + + /* api callbacks */ + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = actkeys_lassoselect_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); + RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); +} + +/* ------------------- */ + +static int action_circle_select_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; + + KeyframeEdit_CircleData data = {0}; + rctf rect_fl; + + float x = RNA_int_get(op->ptr, "x"); + float y = RNA_int_get(op->ptr, "y"); + float radius = RNA_int_get(op->ptr, "radius"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data.mval[0] = x; + data.mval[1] = y; + data.radius_squared = radius * radius; + data.rectf_view = &rect_fl; + + rect_fl.xmin = x - radius; + rect_fl.xmax = x + radius; + rect_fl.ymin = y - radius; + rect_fl.ymax = y + radius; + + /* apply region select action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_select_circle(wmOperatorType *ot) +{ + ot->name = "Circle Select"; + ot->description = "Select keyframe points using circle selection"; + ot->idname = "ACTION_OT_select_circle"; + + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = action_circle_select_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX); + RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX); +} + /* ******************** Column Select Operator **************************** */ /* This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 8c058d23cde..67b960bfa53 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -415,7 +415,7 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; - KeyframeEdit_LassoData data_lasso; + KeyframeEdit_LassoData data_lasso = {0}; rcti rect; rctf rect_fl; @@ -423,7 +423,6 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) bool incl_handles; bool extend; - /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; @@ -501,7 +500,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; bool incl_handles = false; - KeyframeEdit_CircleData data; + KeyframeEdit_CircleData data = {0}; rctf rect_fl; float x = RNA_int_get(op->ptr, "x"); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index a51648290db..8968c2a4543 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -4208,7 +4208,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "MASK_OT_select_circle"); WM_modalkeymap_assign(keymap, "NODE_OT_select_circle"); WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle"); - WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); + WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); + WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle"); } -- cgit v1.2.3 From 833e69ff7ead32f20cce36f3a1dfe90f80020ea1 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 24 Jun 2016 02:52:13 +1200 Subject: DopeSheet: GPencil-Mode supports Circle and Lasso Select To get this working the least effort, I've had to expose the helper functions used by the lasso and circle select keyframe-test callbacks (which are generic) and expose them for use by the GP keyframe editing code too. Hopefully in time we clean this all up and just write the code once to operate on "keyframes" --- source/blender/editors/animation/keyframes_edit.c | 12 ++++----- .../blender/editors/gpencil/editaction_gpencil.c | 30 ++++++++++++++++++++++ source/blender/editors/include/ED_gpencil.h | 2 ++ source/blender/editors/include/ED_keyframes_edit.h | 12 +++++++++ .../blender/editors/space_action/action_select.c | 4 +-- 5 files changed, 52 insertions(+), 8 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index f909b39cca3..7b35a154fc8 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -541,7 +541,7 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt) /** * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso */ -static bool bezier_region_lasso_test( +bool keyframe_region_lasso_test( const KeyframeEdit_LassoData *data_lasso, const float xy[2]) { @@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) if (ked->data) { short ok = 0; -#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index]) +#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index]) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -596,7 +596,7 @@ static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt) pt[0] = bezt->vec[1][0]; pt[1] = ked->channel_y; - if (bezier_region_lasso_test(data, pt)) + if (keyframe_region_lasso_test(data, pt)) return KEYFRAME_OK_KEY; } return 0; @@ -605,7 +605,7 @@ static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt) /** * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle */ -static bool bezier_region_circle_test( +bool keyframe_region_circle_test( const KeyframeEdit_CircleData *data_circle, const float xy[2]) { @@ -629,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) if (ked->data) { short ok = 0; -#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index]) +#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index]) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -661,7 +661,7 @@ static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt) pt[0] = bezt->vec[1][0]; pt[1] = ked->channel_y; - if (bezier_region_circle_test(data, pt)) + if (keyframe_region_circle_test(data, pt)) return KEYFRAME_OK_KEY; } return 0; diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index a49b3362155..738496a67c6 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short } } +/* select the frames in this layer that occur within the lasso/circle region specified */ +void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode) +{ + bGPDframe *gpf; + + if (gpl == NULL) + return; + + /* only select frames which are within the region */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* construct a dummy point coordinate to do this testing with */ + float pt[2] = {0}; + + pt[0] = gpf->framenum; + pt[1] = ked->channel_y; + + /* check the necessary regions */ + if (tool == BEZT_OK_CHANNEL_LASSO) { + /* Lasso */ + if (keyframe_region_lasso_test(ked->data, pt)) + gpframe_select(gpf, select_mode); + } + else if (tool == BEZT_OK_CHANNEL_CIRCLE) { + /* Circle */ + if (keyframe_region_circle_test(ked->data, pt)) + gpframe_select(gpf, select_mode); + } + } +} + /* ***************************************** */ /* Frame Editing Tools */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 255827db373..de5ab80a88f 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -42,6 +42,7 @@ struct bGPDlayer; struct bGPDframe; struct bGPDstroke; struct bAnimContext; +struct KeyframeEditData; struct PointerRNA; struct wmWindowManager; struct wmKeyConfig; @@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl); void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode); void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode); +void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode); void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode); void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode); diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index 0d352ab5ead..c0eb88cd982 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -266,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt); */ void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt); +/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */ +/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */ + +bool keyframe_region_lasso_test( + const KeyframeEdit_LassoData *data_lasso, + const float xy[2]); + +bool keyframe_region_circle_test( + const KeyframeEdit_CircleData *data_circle, + const float xy[2]); + + /* ************************************************ */ /* Destructive Editing API (keyframes_general.c) */ diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index c9a4922eb0b..62050f129a9 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -468,13 +468,13 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, bGPdata *gpd = ale->data; bGPDlayer *gpl; for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - //ED_gplayer_frames_select_border(gpl, rectf.xmin, rectf.xmax, selectmode); + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); } break; } case ANIMTYPE_GPLAYER: { - //ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode); + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); break; } case ANIMTYPE_MASKDATABLOCK: -- cgit v1.2.3 From 9466829eade042a45221b22b69575e1e3d5864a6 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 24 Jun 2016 02:57:03 +1200 Subject: DopeSheet Mask Mode: Circle/Lasso support Adapted from the code for Grease Pencil (just like the whole mode was) --- source/blender/editors/include/ED_mask.h | 2 ++ source/blender/editors/mask/mask_editaction.c | 30 ++++++++++++++++++++++ .../blender/editors/space_action/action_select.c | 4 +-- 3 files changed, 34 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 1f13b46ff2a..2ab788d5e2a 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -35,6 +35,7 @@ struct bContext; struct wmKeyConfig; struct MaskLayer; struct MaskLayerShape; +struct KeyframeEditData; /* mask_edit.c */ void ED_mask_get_size(struct ScrArea *sa, int *width, int *height); @@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo bool ED_masklayer_frame_select_check(struct MaskLayer *masklay); void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode); void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode); +void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode); void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode); void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode); diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c index bcf9ee5c88d..16147bdc7f8 100644 --- a/source/blender/editors/mask/mask_editaction.c +++ b/source/blender/editors/mask/mask_editaction.c @@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max, } } +/* select the frames in this layer that occur within the lasso/circle region specified */ +void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode) +{ + MaskLayerShape *masklay_shape; + + if (masklay == NULL) + return; + + /* only select frames which are within the region */ + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { + /* construct a dummy point coordinate to do this testing with */ + float pt[2] = {0}; + + pt[0] = masklay_shape->frame; + pt[1] = ked->channel_y; + + /* check the necessary regions */ + if (tool == BEZT_OK_CHANNEL_LASSO) { + /* Lasso */ + if (keyframe_region_lasso_test(ked->data, pt)) + masklayshape_select(masklay_shape, select_mode); + } + else if (tool == BEZT_OK_CHANNEL_CIRCLE) { + /* Circle */ + if (keyframe_region_circle_test(ked->data, pt)) + masklayshape_select(masklay_shape, select_mode); + } + } +} + /* ***************************************** */ /* Frame Editing Tools */ diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 62050f129a9..0b6d3cb1f60 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -482,13 +482,13 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, Mask *mask = ale->data; MaskLayer *masklay; for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - //ED_masklayer_frames_select_border(masklay, rectf.xmin, rectf.xmax, selectmode); + ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode); } break; } case ANIMTYPE_MASKLAYER: { - //ED_masklayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode); + ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode); break; } default: -- cgit v1.2.3 From 9839aba84fe5a400705f4fe049b91f25c6de7607 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 24 Jun 2016 03:15:55 +1200 Subject: Fix minor typo - Was m[3][4] instead of m[4][4] for a 4x4 matrix --- source/blender/blenlib/BLI_math_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 9120d9f53f7..8124e07dd47 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -273,7 +273,7 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float /*********************************** Other ***********************************/ void print_m3(const char *str, float M[3][3]); -void print_m4(const char *str, float M[3][4]); +void print_m4(const char *str, float M[4][4]); #define print_m3_id(M) print_m3(STRINGIFY(M), M) #define print_m4_id(M) print_m4(STRINGIFY(M), M) -- cgit v1.2.3 From 2af4c80be6d1888fc9bb34e67518ded8e8b1beff Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 24 Jun 2016 03:33:31 +1200 Subject: GPencil: Eraser respects "Selection Mask" when in EditMode --- source/blender/editors/gpencil/gpencil_paint.c | 46 ++++++++++++++++++-------- 1 file changed, 32 insertions(+), 14 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index fba2f30e715..a570d586f50 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result { typedef enum eGPencil_PaintFlags { GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */ GP_PAINTFLAG_STROKEADDED = (1 << 1), - GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2) + GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2), + GP_PAINTFLAG_SELECTMASK = (1 << 3), } eGPencil_PaintFlags; @@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, BLI_freelinkN(&gpf->strokes, gps); } else if (gps->totpoints == 1) { - gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); - - /* do boundbox check first */ - if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { - /* only check if point is inside */ - if (len_v2v2_int(mval, pc1) <= radius) { - /* free stroke */ - // XXX: pressure sensitive eraser should apply here too? - MEM_freeN(gps->points); - if (gps->triangles) - MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + /* only process if it hasn't been masked out... */ + if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { + gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); + + /* do boundbox check first */ + if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { + /* only check if point is inside */ + if (len_v2v2_int(mval, pc1) <= radius) { + /* free stroke */ + // XXX: pressure sensitive eraser should apply here too? + MEM_freeN(gps->points); + if (gps->triangles) + MEM_freeN(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + } } } } @@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, pt1 = gps->points + i; pt2 = gps->points + i + 1; + /* only process if it hasn't been masked out... */ + if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) + continue; + + /* get coordinates of point in screenspace */ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); @@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p) static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) { Scene *scene = p->scene; + ToolSettings *ts = scene->toolsettings; /* get active layer (or add a new one if non-existent) */ p->gpl = gpencil_layer_getactive(p->gpd); @@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) /* Ensure this gets set... */ p->gpf = p->gpl->actframe; + /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on + * (though this is only available in editmode) + */ + if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) { + if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) { + p->flags |= GP_PAINTFLAG_SELECTMASK; + } + } + if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; //if (G.debug & G_DEBUG) @@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) } else { /* Drawing Modes - Add a new frame if needed on the active layer */ - ToolSettings *ts = p->scene->toolsettings; short add_frame_mode; if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) -- cgit v1.2.3 From 23c276832b1bb43712756c0ea3af954557ab05e7 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Thu, 23 Jun 2016 22:56:43 +0200 Subject: Cycles: Add multi-scattering, energy-conserving GGX as an option to the Glossy, Anisotropic and Glass BSDFs This commit adds a new distribution to the Glossy, Anisotropic and Glass BSDFs that implements the multiple-scattering microfacet model described in the paper "Multiple-Scattering Microfacet BSDFs with the Smith Model". Essentially, the improvement is that unlike classical GGX, which only models single scattering and assumes the contribution of multiple bounces to be zero, this new model performs a random walk on the microsurface until the ray leaves it again, which ensures perfect energy conservation. In practise, this means that the "darkening problem" - GGX materials becoming darker with increasing roughness - is solved in a physically correct and efficient way. The downside of this model is that it has no (known) analytic expression for evalation. However, it can be evaluated stochastically, and although the correct PDF isn't known either, the properties of MIS and the balance heuristic guarantee an unbiased result at the cost of slightly higher noise. Reviewers: dingto, #cycles, brecht Reviewed By: dingto, #cycles, brecht Subscribers: bliblubli, ace_dragon, gregzaal, brecht, harvester, dingto, marcog, swerner, jtheninja, Blendify, nutel Differential Revision: https://developer.blender.org/D2002 --- source/blender/makesdna/DNA_node_types.h | 3 ++- source/blender/makesrna/intern/rna_nodetree.c | 21 +++++++++++++++++++++ source/blender/nodes/NOD_static_types.h | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6cba3322135..46b30f41f5b 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -912,7 +912,8 @@ typedef struct NodeSunBeams { #define SHD_GLOSSY_BECKMANN 0 #define SHD_GLOSSY_SHARP 1 #define SHD_GLOSSY_GGX 2 -#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_MULTI_GGX 4 /* vector transform */ #define SHD_VECT_TRANSFORM_TYPE_VECTOR 0 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index bf7e4634c2f..7f2cd1e6080 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3193,17 +3193,27 @@ static EnumPropertyItem node_glossy_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem node_anisotropic_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem node_glass_items[] = { + {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, + {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, + {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_refraction_items[] = { {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, @@ -4159,6 +4169,17 @@ static void def_glass(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_refraction(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, node_refraction_items); + RNA_def_property_ui_text(prop, "Distribution", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_anisotropic(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 9e1a0c926fa..171d5313c1d 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -82,7 +82,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BS DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" ) -DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) +DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" ) -- cgit v1.2.3 From 4fc1510dd8f2cac70ac4e0e813c82a88fe462e15 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 24 Jun 2016 10:05:09 +1000 Subject: Cleanup: use return argument prefix --- source/blender/editors/include/UI_interface.h | 12 +++++++++--- source/blender/editors/interface/interface_handlers.c | 17 +++++++++-------- source/blender/editors/interface/interface_templates.c | 12 +++++++----- 3 files changed, 25 insertions(+), 16 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9aad340d2fb..a623f5cfb9c 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list( /* Helpers for Operators */ uiBut *UI_context_active_but_get(const struct bContext *C); -void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index); +void UI_context_active_but_prop_get( + const struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index); void UI_context_active_but_prop_handle(struct bContext *C); struct wmOperator *UI_context_active_operator_get(const struct bContext *C); void UI_context_update_anim_flag(const struct bContext *C); -void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo); -void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop); +void UI_context_active_but_prop_get_filebrowser( + const struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo); +void UI_context_active_but_prop_get_templateID( + struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop); /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 133487e1846..dd823891290 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -8013,20 +8013,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C) } /* helper function for insert keyframe, reset to default, etc operators */ -void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index) +void UI_context_active_but_prop_get( + const bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index) { uiBut *activebut = ui_context_rna_button_active(C); - memset(ptr, 0, sizeof(*ptr)); - if (activebut && activebut->rnapoin.data) { - *ptr = activebut->rnapoin; - *prop = activebut->rnaprop; - *index = activebut->rnaindex; + *r_ptr = activebut->rnapoin; + *r_prop = activebut->rnaprop; + *r_index = activebut->rnaindex; } else { - *prop = NULL; - *index = 0; + memset(r_ptr, 0, sizeof(*r_ptr)); + *r_prop = NULL; + *r_index = 0; } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 9f0c4b16523..7f276bcc634 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -232,15 +232,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem) /* This is for browsing and editing the ID-blocks used */ /* for new/open operators */ -void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop) +void UI_context_active_but_prop_get_templateID( + bContext *C, + PointerRNA *r_ptr, PropertyRNA **r_prop) { TemplateID *template; ARegion *ar = CTX_wm_region(C); uiBlock *block; uiBut *but; - memset(ptr, 0, sizeof(*ptr)); - *prop = NULL; + memset(r_ptr, 0, sizeof(*r_ptr)); + *r_prop = NULL; if (!ar) return; @@ -251,8 +253,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) { if (but->func_argN) { template = but->func_argN; - *ptr = template->ptr; - *prop = template->prop; + *r_ptr = template->ptr; + *r_prop = template->prop; return; } } -- cgit v1.2.3 From 25866aa149968919a5b4ea01b94c5f31227cbd71 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 24 Jun 2016 10:05:18 +1000 Subject: BKE_blender: Add own atexit functions Runs before guarded-alloc leaks print. --- source/blender/blenkernel/BKE_blender.h | 5 ++ source/blender/blenkernel/intern/blender.c | 53 ++++++++++++++++++++++ source/blender/windowmanager/intern/wm_init_exit.c | 2 + 3 files changed, 60 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 8ce85c8e615..d2d9c763031 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -50,6 +50,11 @@ void BKE_blender_userdef_refresh(void); void BKE_blender_callback_test_break_set(void (*func)(void)); int BKE_blender_test_break(void); +/* Blenders' own atexit (avoids leaking) */ +void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data); +void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data); +void BKE_blender_atexit(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 15492fbd20d..0805335da66 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -226,3 +226,56 @@ int BKE_blender_test_break(void) return (G.is_break == true); } + +/** \name Blender's AtExit + * + * \note Don't use MEM_mallocN so functions can be registered at any time. + * \{ */ + +struct AtExitData { + struct AtExitData *next; + + void (*func)(void *user_data); + void *user_data; +} *g_atexit = NULL; + +void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data) +{ + struct AtExitData *ae = malloc(sizeof(*ae)); + ae->next = g_atexit; + ae->func = func; + ae->user_data = user_data; + g_atexit = ae; +} + +void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data) +{ + struct AtExitData *ae = g_atexit; + struct AtExitData **ae_p = &g_atexit; + + while (ae) { + if ((ae->func == func) && (ae->user_data == user_data)) { + *ae_p = ae->next; + free(ae); + return; + } + ae_p = &ae; + ae = ae->next; + } +} + +void BKE_blender_atexit(void) +{ + struct AtExitData *ae = g_atexit, *ae_next; + while (ae) { + ae_next = ae->next; + + ae->func(ae->user_data); + + free(ae); + ae = ae_next; + } + g_atexit = NULL; +} + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index a1ca89c6a8c..2c9deb05328 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -579,6 +579,8 @@ void WM_exit_ext(bContext *C, const bool do_python) BLI_threadapi_exit(); + BKE_blender_atexit(); + if (MEM_get_memory_blocks_in_use() != 0) { size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use(); printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", -- cgit v1.2.3 From 73a9c56607272be410b8e87336f4e05d87a44ed5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 24 Jun 2016 18:58:42 +1000 Subject: Fix T48716: Knife cut creates inverted normals In the case of having 3+ boundary edges, we need to find the best. --- .../blender/bmesh/intern/bmesh_polygon_edgenet.c | 44 ++++++++++++---------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'source/blender') diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index 5ef19b58c9d..5c07ffcc0d0 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -142,10 +142,17 @@ static bool bm_face_split_edgenet_find_loop_pair( } e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary); + /* use to hold boundary OR wire edges */ + BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *); + /* attempt one boundary and one wire, or 2 boundary */ if (edges_wire_len == 0) { - if (edges_boundary_len >= 2) { + if (edges_boundary_len > 1) { e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); + + if (edges_boundary_len > 2) { + BLI_SMALLSTACK_SWAP(edges_search, edges_wire); + } } else { /* one boundary and no wire */ @@ -154,28 +161,27 @@ static bool bm_face_split_edgenet_find_loop_pair( } else { e_pair[1] = BLI_SMALLSTACK_POP(edges_wire); - if (edges_wire_len > 1) { - BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); - BMVert *v_next; - float angle_best; - - v_next = BM_edge_other_vert(e_pair[1], v_init); - angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - - BMEdge *e; - while ((e = BLI_SMALLSTACK_POP(edges_wire))) { - float angle_test; - v_next = BM_edge_other_vert(e, v_init); - angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - if (angle_test < angle_best) { - angle_best = angle_test; - e_pair[1] = e; - } - } + BLI_SMALLSTACK_SWAP(edges_search, edges_wire); } } + /* if we swapped above, search this list for the best edge */ + if (!BLI_SMALLSTACK_IS_EMPTY(edges_search)) { + /* find the best edge in 'edge_list' to use for 'e_pair[1]' */ + const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); + const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init); + float angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); + BMEdge *e; + while ((e = BLI_SMALLSTACK_POP(edges_search))) { + v_next = BM_edge_other_vert(e, v_init); + const float angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); + if (angle_test < angle_best) { + angle_best = angle_test; + e_pair[1] = e; + } + } + } /* flip based on winding */ l_walk = bm_edge_flagged_radial_first(e_pair[0]); -- cgit v1.2.3 From a10117562fd1783817120a35143d0d3837dc92f0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 24 Jun 2016 18:59:02 +1000 Subject: BMesh: avoid redundant calculations comparing angles --- .../blender/bmesh/intern/bmesh_polygon_edgenet.c | 42 +++++++++++++++++----- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'source/blender') diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index 5c07ffcc0d0..5ee0e904a33 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -97,12 +97,22 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e) return NULL; } +static void normalize_v2_m3_v3v3(float out[2], float axis_mat[3][3], const float v1[3], const float v2[3]) +{ + float dir[3]; + sub_v3_v3v3(dir, v1, v2); + mul_v2_m3v3(out, axis_mat, dir); + normalize_v2(out); +} + + /** * \note Be sure to update #bm_face_split_edgenet_find_loop_pair_exists * when making changed to edge picking logic. */ static bool bm_face_split_edgenet_find_loop_pair( - BMVert *v_init, const float face_normal[3], + BMVert *v_init, + const float face_normal[3], float face_normal_matrix[3][3], BMEdge *e_pair[2]) { /* Always find one boundary edge (to determine winding) @@ -171,13 +181,23 @@ static bool bm_face_split_edgenet_find_loop_pair( /* find the best edge in 'edge_list' to use for 'e_pair[1]' */ const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init); - float angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); + + float dir_prev[2], dir_next[2]; + + normalize_v2_m3_v3v3(dir_prev, face_normal_matrix, v_prev->co, v_init->co); + normalize_v2_m3_v3v3(dir_next, face_normal_matrix, v_next->co, v_init->co); + float angle_best_cos = dot_v2v2(dir_next, dir_prev); + BMEdge *e; while ((e = BLI_SMALLSTACK_POP(edges_search))) { v_next = BM_edge_other_vert(e, v_init); - const float angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - if (angle_test < angle_best) { - angle_best = angle_test; + float dir_test[2]; + + normalize_v2_m3_v3v3(dir_test, face_normal_matrix, v_next->co, v_init->co); + const float angle_test_cos = dot_v2v2(dir_prev, dir_test); + + if (angle_test_cos > angle_best_cos) { + angle_best_cos = angle_test_cos; e_pair[1] = e; } } @@ -398,7 +418,7 @@ finally: } static bool bm_face_split_edgenet_find_loop( - BMVert *v_init, const float face_normal[3], + BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3], /* cache to avoid realloc every time */ struct VertOrder *edge_order, const unsigned int edge_order_len, BMVert **r_face_verts, int *r_face_verts_len) @@ -406,7 +426,7 @@ static bool bm_face_split_edgenet_find_loop( BMEdge *e_pair[2]; BMVert *v; - if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) { + if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, face_normal_matrix, e_pair)) { return false; } @@ -501,12 +521,18 @@ bool BM_face_split_edgenet( BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET); } while ((l_iter = l_iter->next) != l_first); + float face_normal_matrix[3][3]; + axis_dominant_v3_to_m3(face_normal_matrix, f->no); + /* any vert can be used to begin with */ STACK_PUSH(vert_queue, l_first->v); while ((v = STACK_POP(vert_queue))) { - if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) { + if (bm_face_split_edgenet_find_loop( + v, f->no, face_normal_matrix, + edge_order, edge_order_len, face_verts, &face_verts_len)) + { BMFace *f_new; f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false); -- cgit v1.2.3 From c376ff26beefb0590988fd15fc78eec1c82d155a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 24 Jun 2016 11:00:19 +0200 Subject: Fix T48725: UI message typo. --- source/blender/editors/object/object_relations.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 2f10f83e276..94d1a258063 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -437,7 +437,7 @@ typedef enum eObClearParentTypes { EnumPropertyItem prop_clear_parent_types[] = { {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent", - "Completely clear the parenting relationship, including involved modifiers is any"}, + "Completely clear the parenting relationship, including involved modifiers if any"}, {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", "As 'Clear Parent', but keep the current visual transformations of the object"}, {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse", -- cgit v1.2.3 From 8f0a44a5d55d0f348c924d75be10565e8cecb6ab Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 25 Jun 2016 11:24:25 +1000 Subject: Cleanup: use BLI_bitmap for bevel-split --- source/blender/blenkernel/BKE_displist.h | 14 +++++++++----- source/blender/blenkernel/intern/displist.c | 12 ++++++------ source/blender/render/intern/source/convertblender.c | 15 ++++++++++----- 3 files changed, 25 insertions(+), 16 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 3b096773d96..9625f05192a 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -45,10 +45,14 @@ #define DL_VERTS 7 /* dl->flag */ -#define DL_CYCL_U 1 -#define DL_CYCL_V 2 -#define DL_FRONT_CURVE 4 -#define DL_BACK_CURVE 8 +enum { + /** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */ + DL_CYCL_U = (1 << 0), + DL_CYCL_V = (1 << 1), + + DL_FRONT_CURVE = (1 << 2), + DL_BACK_CURVE = (1 << 3), +}; /* prototypes */ @@ -70,7 +74,7 @@ typedef struct DispList { int charidx; int totindex; /* indexed array drawing surfaces */ - unsigned int *bevelSplitFlag; + unsigned int *bevel_split; /* BLI_bitmap */ } DispList; void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb); diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 98cbe47c7f9..b69141f1856 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -71,7 +71,7 @@ void BKE_displist_elem_free(DispList *dl) if (dl->verts) MEM_freeN(dl->verts); if (dl->nors) MEM_freeN(dl->nors); if (dl->index) MEM_freeN(dl->index); - if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag); + if (dl->bevel_split) MEM_freeN(dl->bevel_split); MEM_freeN(dl); } } @@ -144,8 +144,9 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb) dln->nors = MEM_dupallocN(dl->nors); dln->index = MEM_dupallocN(dl->index); - if (dl->bevelSplitFlag) - dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag); + if (dl->bevel_split) { + dln->bevel_split = MEM_dupallocN(dl->bevel_split); + } dl = dl->next; } @@ -1642,8 +1643,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt = nu->flag & ~CU_2D; - dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5), - "bevelSplitFlag"); + dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split"); /* for each point of poly make a bevel piece */ bevp_first = bl->bevpoints; @@ -1683,7 +1683,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } if (bevp->split_tag) { - dl->bevelSplitFlag[a >> 5] |= 1 << (a & 0x1F); + BLI_BITMAP_ENABLE(dl->bevel_split, a); } /* rotate bevel piece and write in data */ diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 8c847773d75..9948ac99814 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -2816,7 +2816,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) } } - if (dl->bevelSplitFlag || timeoffset==0) { + if (dl->bevel_split || timeoffset == 0) { const int startvlak= obr->totvlak; for (a=0; aparts; a++) { @@ -2856,10 +2856,15 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) } } - if (dl->bevelSplitFlag) { - for (a=0; aparts-1+!!(dl->flag&DL_CYCL_V); a++) - if (dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F))) - split_v_renderfaces(obr, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U); + if (dl->bevel_split) { + for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) { + if (BLI_BITMAP_TEST(dl->bevel_split, a)) { + split_v_renderfaces( + obr, startvlak, startvert, dl->parts, dl->nr, a, + /* intentionally swap (v, u) --> (u, v) */ + dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U); + } + } } /* vertex normals */ -- cgit v1.2.3 From 05a60aaa07e7c63399fe94f43793a801a88d1e71 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 25 Jun 2016 13:57:35 +1000 Subject: Fix T48723: Curve bevel creates invalid geometry --- source/blender/blenkernel/intern/displist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index b69141f1856..49db75a0474 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -1630,7 +1630,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba if (dlb->type == DL_POLY) { dl->flag |= DL_CYCL_U; } - if ((bl->poly >= 0) && (steps != 2)) { + if ((bl->poly >= 0) && (steps > 2)) { dl->flag |= DL_CYCL_V; } -- cgit v1.2.3 From 0a99072f0d88f6fa809680dfcabe7aba5d476e0a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 25 Jun 2016 20:16:33 +1000 Subject: GPU: move select index code out of WM This avoids bad-level calls. --- source/blender/blenkernel/intern/cdderivedmesh.c | 6 +- source/blender/editors/mesh/editface.c | 3 +- source/blender/editors/space_view3d/drawobject.c | 18 +-- source/blender/editors/space_view3d/view3d_draw.c | 4 +- .../blender/editors/space_view3d/view3d_select.c | 4 +- source/blender/gpu/GPU_draw.h | 6 + source/blender/gpu/intern/gpu_draw.c | 149 +++++++++++++++++++++ source/blender/windowmanager/WM_api.h | 6 - source/blender/windowmanager/intern/wm_subwindow.c | 144 -------------------- source/blender/windowmanager/wm_subwindow.h | 2 - 10 files changed, 173 insertions(+), 169 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 267f7a65e00..159d5b82a6c 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -61,8 +61,6 @@ #include "GPU_shader.h" #include "GPU_basic_shader.h" -#include "WM_api.h" - #include #include #include @@ -699,10 +697,10 @@ static void cdDM_drawMappedFaces( } if ((orig != ORIGINDEX_NONE) && !is_hidden) - WM_framebuffer_index_get(orig + 1, &selcol); + GPU_select_index_get(orig + 1, &selcol); } else if (orig != ORIGINDEX_NONE) - WM_framebuffer_index_get(orig + 1, &selcol); + GPU_select_index_get(orig + 1, &selcol); for (j = 0; j < mpoly->totloop; j++) fi_map[start_element++] = selcol; diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 01be8f848aa..c4e87614732 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -53,6 +53,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_draw.h" #include "GPU_buffers.h" /* own include */ @@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten if (ENDIAN_ORDER == B_ENDIAN) { IMB_convert_rgba_to_abgr(ibuf); } - WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]); + GPU_select_to_index_array(ibuf->rect, size[0] * size[1]); a = size[0] * size[1]; while (a--) { diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 76c19fbb8d3..715666886e2 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -8219,7 +8219,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa MVert *mv = &data->mvert[index]; if (!(mv->flag & ME_HIDE)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); glVertex3fv(co); } } @@ -8244,7 +8244,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3] BMVert *eve = BM_vert_at_index(data->bm, index); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); glVertex3fv(co); } } @@ -8263,7 +8263,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index) BMEdge *eed = BM_edge_at_index(data->bm, index); if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); return DM_DRAW_OPTION_NORMAL; } else { @@ -8277,7 +8277,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) } /** - * dont set #WM_framebuffer_index_set. just use to mask other + * dont set #GPU_framebuffer_index_set. just use to mask other */ static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index) { @@ -8296,7 +8296,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } else { @@ -8309,7 +8309,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); glVertex3fv(cent); } @@ -8340,7 +8340,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } @@ -8349,7 +8349,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) Mesh *me = userData; if (!(me->mpoly[index].flag & ME_HIDE)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } else { @@ -8357,7 +8357,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) } } -/* must have called WM_framebuffer_index_set beforehand */ +/* must have called GPU_framebuffer_index_set beforehand */ static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index) { Mesh *me = userData; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 9fb990b35a0..329778cd716 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1488,7 +1488,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) BLI_endian_switch_uint32(&col); } - return WM_framebuffer_to_index(col); + return GPU_select_to_index(col); } /* reads full rect, converts indices */ @@ -1521,7 +1521,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int IMB_convert_rgba_to_abgr(ibuf_clip); } - WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); + GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); if ((clip.xmin == xmin) && (clip.xmax == xmax) && diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index bedcf413bfa..a460d8900b4 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -94,6 +94,8 @@ #include "UI_interface.h" +#include "GPU_draw.h" + #include "view3d_intern.h" /* own include */ float ED_view3d_select_dist_px(void) @@ -1690,7 +1692,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo if (ENDIAN_ORDER == B_ENDIAN) { IMB_convert_rgba_to_abgr(ibuf); } - WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]); + GPU_select_to_index_array(ibuf->rect, size[0] * size[1]); a = size[0] * size[1]; while (a--) { diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index bc732387c85..90b65af87c8 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -160,6 +160,12 @@ struct DerivedMesh; void GPU_draw_update_fvar_offset(struct DerivedMesh *dm); #endif +/* utilities */ +void GPU_select_index_set(int index); +void GPU_select_index_get(int index, int *r_col); +int GPU_select_to_index(unsigned int col); +void GPU_select_to_index_array(unsigned int *col, const unsigned int size); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 89816b09024..064e91743e8 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -2361,3 +2361,152 @@ void GPU_draw_update_fvar_offset(DerivedMesh *dm) } } #endif + + +/** \name Framebuffer color depth, for selection codes + * \{ */ + +#ifdef __APPLE__ + +/* apple seems to round colors to below and up on some configs */ + +static unsigned int index_to_framebuffer(int index) +{ + unsigned int i = index; + + switch (GPU_color_depth()) { + case 12: + i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); + /* sometimes dithering subtracts! */ + i |= 0x070707; + break; + case 15: + case 16: + i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); + i |= 0x030303; + break; + case 24: + break; + default: /* 18 bits... */ + i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); + i |= 0x010101; + break; + } + + return i; +} + +#else + +/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */ + +static unsigned int index_to_framebuffer(int index) +{ + unsigned int i = index; + + switch (GPU_color_depth()) { + case 8: + i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6); + i |= 0x3F3F3F; + break; + case 12: + i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); + /* sometimes dithering subtracts! */ + i |= 0x0F0F0F; + break; + case 15: + case 16: + i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); + i |= 0x070707; + break; + case 24: + break; + default: /* 18 bits... */ + i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); + i |= 0x030303; + break; + } + + return i; +} + +#endif + + +void GPU_select_index_set(int index) +{ + const int col = index_to_framebuffer(index); + glColor3ub(( (col) & 0xFF), + (((col) >> 8) & 0xFF), + (((col) >> 16) & 0xFF)); +} + +void GPU_select_index_get(int index, int *r_col) +{ + const int col = index_to_framebuffer(index); + char *c_col = (char *)r_col; + c_col[0] = (col & 0xFF); /* red */ + c_col[1] = ((col >> 8) & 0xFF); /* green */ + c_col[2] = ((col >> 16) & 0xFF); /* blue */ + c_col[3] = 0xFF; /* alpha */ +} + + +#define INDEX_FROM_BUF_8(col) ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6)) +#define INDEX_FROM_BUF_12(col) ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8) + (((col) & 0xF0) >> 4)) +#define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9) + (((col) & 0xF800) >> 6) + (((col) & 0xF8) >> 3)) +#define INDEX_FROM_BUF_18(col) ((((col) & 0xFC0000) >> 6) + (((col) & 0xFC00) >> 4) + (((col) & 0xFC) >> 2)) +#define INDEX_FROM_BUF_24(col) ((col) & 0xFFFFFF) + +int GPU_select_to_index(unsigned int col) +{ + if (col == 0) { + return 0; + } + + switch (GPU_color_depth()) { + case 8: return INDEX_FROM_BUF_8(col); + case 12: return INDEX_FROM_BUF_12(col); + case 15: + case 16: return INDEX_FROM_BUF_15_16(col); + case 24: return INDEX_FROM_BUF_24(col); + default: return INDEX_FROM_BUF_18(col); + } +} + +void GPU_select_to_index_array(unsigned int *col, const unsigned int size) +{ +#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ + for (i = size; i--; col++) { \ + if ((c = *col)) { \ + *col = INDEX_FROM_BUF_BITS(c); \ + } \ + } ((void)0) + + if (size > 0) { + unsigned int i, c; + + switch (GPU_color_depth()) { + case 8: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_8); + break; + case 12: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_12); + break; + case 15: + case 16: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16); + break; + case 24: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_24); + break; + default: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_18); + break; + } + } + +#undef INDEX_BUF_ARRAY +} + +/** \} */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 9bb2462a4e9..7a247d9791b 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -413,12 +413,6 @@ void wmOrtho2 (float x1, float x2, float y1, float y2); void wmOrtho2_region_pixelspace(const struct ARegion *ar); void wmOrtho2_pixelspace(const float x, const float y); - /* utilities */ -void WM_framebuffer_index_set(int index); -void WM_framebuffer_index_get(int index, int *r_col); -int WM_framebuffer_to_index(unsigned int col); -void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size); - /* threaded Jobs Manager */ enum { WM_JOB_PRIORITY = (1 << 0), diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 6526d419914..458ac4a121a 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -378,149 +378,5 @@ void wmOrtho2_pixelspace(const float x, const float y) wmOrtho2_offset(x, y, -GLA_PIXEL_OFS); } -/* *************************** Framebuffer color depth, for selection codes ********************** */ - -#ifdef __APPLE__ - -/* apple seems to round colors to below and up on some configs */ - -unsigned int index_to_framebuffer(int index) -{ - unsigned int i = index; - - switch (GPU_color_depth()) { - case 12: - i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); - /* sometimes dithering subtracts! */ - i |= 0x070707; - break; - case 15: - case 16: - i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); - i |= 0x030303; - break; - case 24: - break; - default: /* 18 bits... */ - i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); - i |= 0x010101; - break; - } - - return i; -} - -#else - -/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */ - -unsigned int index_to_framebuffer(int index) -{ - unsigned int i = index; - - switch (GPU_color_depth()) { - case 8: - i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6); - i |= 0x3F3F3F; - break; - case 12: - i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); - /* sometimes dithering subtracts! */ - i |= 0x0F0F0F; - break; - case 15: - case 16: - i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); - i |= 0x070707; - break; - case 24: - break; - default: /* 18 bits... */ - i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); - i |= 0x030303; - break; - } - - return i; -} - -#endif - -void WM_framebuffer_index_set(int index) -{ - const int col = index_to_framebuffer(index); - cpack(col); -} - -void WM_framebuffer_index_get(int index, int *r_col) -{ - const int col = index_to_framebuffer(index); - char *c_col = (char *)r_col; - c_col[0] = (col & 0xFF); /* red */ - c_col[1] = ((col >> 8) & 0xFF); /* green */ - c_col[2] = ((col >> 16) & 0xFF); /* blue */ - c_col[3] = 0xFF; /* alpha */ -} - - - -#define INDEX_FROM_BUF_8(col) (((col & 0xC00000) >> 18) + ((col & 0xC000) >> 12) + ((col & 0xC0) >> 6)) -#define INDEX_FROM_BUF_12(col) (((col & 0xF00000) >> 12) + ((col & 0xF000) >> 8) + ((col & 0xF0) >> 4)) -#define INDEX_FROM_BUF_15_16(col) (((col & 0xF80000) >> 9) + ((col & 0xF800) >> 6) + ((col & 0xF8) >> 3)) -#define INDEX_FROM_BUF_18(col) (((col & 0xFC0000) >> 6) + ((col & 0xFC00) >> 4) + ((col & 0xFC) >> 2)) -#define INDEX_FROM_BUF_24(col) (col & 0xFFFFFF) - -int WM_framebuffer_to_index(unsigned int col) -{ - if (col == 0) { - return 0; - } - - switch (GPU_color_depth()) { - case 8: return INDEX_FROM_BUF_8(col); - case 12: return INDEX_FROM_BUF_12(col); - case 15: - case 16: return INDEX_FROM_BUF_15_16(col); - case 24: return INDEX_FROM_BUF_24(col); - default: return INDEX_FROM_BUF_18(col); - } -} - -void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size) -{ -#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ - for (i = size; i--; col++) { \ - if ((c = *col)) { \ - *col = INDEX_FROM_BUF_BITS(c); \ - } \ - } ((void)0) - - if (size > 0) { - unsigned int i, c; - - switch (GPU_color_depth()) { - case 8: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_8); - break; - case 12: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_12); - break; - case 15: - case 16: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16); - break; - case 24: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_24); - break; - default: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_18); - break; - } - } - -#undef INDEX_BUF_ARRAY -} - - /* ********** END MY WINDOW ************** */ diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h index 2a8118a726b..cc9abf87514 100644 --- a/source/blender/windowmanager/wm_subwindow.h +++ b/source/blender/windowmanager/wm_subwindow.h @@ -48,7 +48,5 @@ void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]); void wm_subwindow_rect_get(wmWindow *win, int swinid, struct rcti *r_rect); void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect); -unsigned int index_to_framebuffer(int index); - #endif /* __WM_SUBWINDOW_H__ */ -- cgit v1.2.3 From 9c96585f3cc09b3e4adc40b53982792974d1d8eb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 25 Jun 2016 21:10:30 +1000 Subject: Cleanup: remove bad-level call --- source/blender/blenkernel/BKE_blender_undo.h | 2 ++ source/blender/blenkernel/CMakeLists.txt | 3 --- source/blender/blenkernel/intern/blender_undo.c | 14 ++++++++++---- source/blender/blenkernel/intern/image.c | 2 -- source/blender/blenkernel/intern/pointcache.c | 2 -- source/blender/windowmanager/intern/wm_init_exit.c | 7 +++++++ 6 files changed, 19 insertions(+), 11 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h index cd18bd8db40..9547eeb9838 100644 --- a/source/blender/blenkernel/BKE_blender_undo.h +++ b/source/blender/blenkernel/BKE_blender_undo.h @@ -45,6 +45,8 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active); extern bool BKE_undo_save_file(const char *filename); extern struct Main *BKE_undo_get_main(struct Scene **r_scene); +extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 6af9f8a71ee..b7ff81d603b 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -49,9 +49,6 @@ set(INC ../../../intern/smoke/extern ../../../intern/atomic ../../../intern/libmv - - # XXX - BAD LEVEL CALL WM_api.h - ../windowmanager ) set(INC_SYS diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index ca0a1b91cea..d64bf7ecf43 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -66,9 +66,6 @@ #include "BLO_readfile.h" #include "BLO_writefile.h" -#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie - - /* -------------------------------------------------------------------- */ /** \name Global Undo @@ -87,6 +84,15 @@ typedef struct UndoElem { static ListBase undobase = {NULL, NULL}; static UndoElem *curundo = NULL; +/** + * Avoid bad-level call to #WM_jobs_kill_all_except() + */ +static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL; + +void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)) +{ + undo_wm_job_kill_callback = callback; +} static int read_undosave(bContext *C, UndoElem *uel) { @@ -94,7 +100,7 @@ static int read_undosave(bContext *C, UndoElem *uel) int success = 0, fileflags; /* This is needed so undoing/redoing doesn't crash with threaded previews going */ - WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); + undo_wm_job_kill_callback(C); BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 14a445649ad..69384a70969 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -95,8 +95,6 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" -#include "WM_api.h" - static SpinLock image_spin; /* prototypes */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 7b8f4986325..e0a3e9743db 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -55,8 +55,6 @@ #include "PIL_time.h" -#include "WM_api.h" - #include "BKE_appdir.h" #include "BKE_anim.h" #include "BKE_cloth.h" diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 2c9deb05328..9d1083bbf63 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -141,6 +141,11 @@ static void wm_free_reports(bContext *C) BKE_reports_clear(reports); } +static void wm_undo_kill_callback(bContext *C) +{ + WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); +} + bool wm_start_with_console = false; /* used in creator.c */ /* only called once, for startup */ @@ -159,6 +164,8 @@ void WM_init(bContext *C, int argc, const char **argv) WM_menutype_init(); WM_uilisttype_init(); + BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback); + BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */ -- cgit v1.2.3 From d4e435836dd9f903f641b55a0b5735e47dc4781f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 25 Jun 2016 17:01:36 +0200 Subject: Cleanup/refactor RNA IDs' `remove` functions. Those (one per ID type!) were uselessly duplicated, and badly inconsistent (some types were actually unlinking before deletion, others were only working if already unlinked!). Now we use same func and same API for all types, by default deletion is performed only if ID is no more used, set `do_unlink` parameter to True to always delete ID even if still in use. Only exception now is with Scene, since we always want to keep at least one! Note that this will change default behavior of some types (since unlinking is never done anymore by default). --- source/blender/makesrna/intern/rna_main_api.c | 440 ++++++-------------------- 1 file changed, 105 insertions(+), 335 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 679f20fab83..c0a0bc0b55a 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -62,6 +62,7 @@ #include "BKE_object.h" #include "BKE_material.h" #include "BKE_icons.h" +#include "BKE_idcode.h" #include "BKE_image.h" #include "BKE_texture.h" #include "BKE_scene.h" @@ -114,30 +115,38 @@ # include "BPY_extern.h" #endif + +static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) +{ + ID *id = id_ptr->data; + if (do_unlink) { + BKE_libblock_delete(bmain, id); + RNA_POINTER_INVALIDATE(id_ptr); + } + else if (ID_REAL_USERS(id) <= 0) { + BKE_libblock_free(bmain, id); + RNA_POINTER_INVALIDATE(id_ptr); + } + else { + BKE_reportf(reports, RPT_ERROR, + "%s '%s' must have zero users to be removed, found %d (try with unlink=True parameter)", + BKE_idcode_to_name(GS(id->name)), id->name + 2, ID_REAL_USERS(id)); + } +} + + static Camera *rna_Main_cameras_new(Main *bmain, const char *name) { ID *id = BKE_camera_add(bmain, name); id_us_min(id); return (Camera *)id; } -static void rna_Main_cameras_remove(Main *bmain, ReportList *reports, PointerRNA *camera_ptr) -{ - Camera *camera = camera_ptr->data; - if (ID_REAL_USERS(camera) <= 0) { - BKE_libblock_free(bmain, camera); - RNA_POINTER_INVALIDATE(camera_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Camera '%s' must have zero users to be removed, found %d", - camera->id.name + 2, ID_REAL_USERS(camera)); - } -} static Scene *rna_Main_scenes_new(Main *bmain, const char *name) { return BKE_scene_add(bmain, name); } -static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr) +static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink) { /* don't call BKE_libblock_free(...) directly */ Scene *scene = scene_ptr->data; @@ -146,24 +155,23 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports if ((scene_new = scene->id.prev) || (scene_new = scene->id.next)) { - bScreen *sc = CTX_wm_screen(C); - if (sc->scene == scene) { + if (do_unlink) { + bScreen *sc = CTX_wm_screen(C); + if (sc->scene == scene) { #ifdef WITH_PYTHON - BPy_BEGIN_ALLOW_THREADS; + BPy_BEGIN_ALLOW_THREADS; #endif - ED_screen_set_scene(C, sc, scene_new); + ED_screen_set_scene(C, sc, scene_new); #ifdef WITH_PYTHON - BPy_END_ALLOW_THREADS; + BPy_END_ALLOW_THREADS; #endif + } } - - BKE_libblock_remap(bmain, scene, scene_new, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); - BKE_libblock_free(bmain, scene); - RNA_POINTER_INVALIDATE(scene_ptr); + rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink); } else { BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2); @@ -224,38 +232,12 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char return ob; } -static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA *object_ptr) -{ - Object *object = object_ptr->data; - if (ID_REAL_USERS(object) <= 0) { - BKE_libblock_unlink(bmain, object, false); - BKE_libblock_free(bmain, object); - RNA_POINTER_INVALIDATE(object_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Object '%s' must have zero users to be removed, found %d", - object->id.name + 2, ID_REAL_USERS(object)); - } -} - static Material *rna_Main_materials_new(Main *bmain, const char *name) { ID *id = (ID *)BKE_material_add(bmain, name); id_us_min(id); return (Material *)id; } -static void rna_Main_materials_remove(Main *bmain, ReportList *reports, PointerRNA *material_ptr) -{ - Material *material = material_ptr->data; - if (ID_REAL_USERS(material) <= 0) { - BKE_libblock_free(bmain, material); - RNA_POINTER_INVALIDATE(material_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Material '%s' must have zero users to be removed, found %d", - material->id.name + 2, ID_REAL_USERS(material)); - } -} static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { @@ -273,18 +255,6 @@ static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, in else return NULL; } -static void rna_Main_nodetree_remove(Main *bmain, ReportList *reports, PointerRNA *ntree_ptr) -{ - bNodeTree *ntree = ntree_ptr->data; - if (ID_REAL_USERS(ntree) <= 0) { - BKE_libblock_free(bmain, ntree); - RNA_POINTER_INVALIDATE(ntree_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Node tree '%s' must have zero users to be removed, found %d", - ntree->id.name + 2, ID_REAL_USERS(ntree)); - } -} static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) { @@ -314,19 +284,6 @@ Mesh *rna_Main_meshes_new_from_object( return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed); } -static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr) -{ - Mesh *mesh = mesh_ptr->data; - if (ID_REAL_USERS(mesh) <= 0) { - BKE_libblock_free(bmain, mesh); - RNA_POINTER_INVALIDATE(mesh_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Mesh '%s' must have zero users to be removed, found %d", - mesh->id.name + 2, ID_REAL_USERS(mesh)); - } -} - static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) { Lamp *lamp = BKE_lamp_add(bmain, name); @@ -334,18 +291,6 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) id_us_min(&lamp->id); return lamp; } -static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *lamp_ptr) -{ - Lamp *lamp = lamp_ptr->data; - if (ID_REAL_USERS(lamp) <= 0) { - BKE_libblock_free(bmain, lamp); - RNA_POINTER_INVALIDATE(lamp_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Lamp '%s' must have zero users to be removed, found %d", - lamp->id.name + 2, ID_REAL_USERS(lamp)); - } -} static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d) { @@ -374,18 +319,6 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char id_us_min((ID *)ima); return ima; } -static void rna_Main_images_remove(Main *bmain, ReportList *reports, PointerRNA *image_ptr) -{ - Image *image = image_ptr->data; - if (ID_REAL_USERS(image) <= 0) { - BKE_libblock_free(bmain, image); - RNA_POINTER_INVALIDATE(image_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Image '%s' must have zero users to be removed, found %d", - image->id.name + 2, ID_REAL_USERS(image)); - } -} static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) { @@ -393,18 +326,6 @@ static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) id_us_min(<->id); return lt; } -static void rna_Main_lattices_remove(Main *bmain, ReportList *reports, PointerRNA *lt_ptr) -{ - Lattice *lt = lt_ptr->data; - if (ID_REAL_USERS(lt) <= 0) { - BKE_libblock_free(bmain, lt); - RNA_POINTER_INVALIDATE(lt_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Lattice '%s' must have zero users to be removed, found %d", - lt->id.name + 2, ID_REAL_USERS(lt)); - } -} static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) { @@ -412,18 +333,6 @@ static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) id_us_min(&cu->id); return cu; } -static void rna_Main_curves_remove(Main *bmain, ReportList *reports, PointerRNA *cu_ptr) -{ - Curve *cu = cu_ptr->data; - if (ID_REAL_USERS(cu) <= 0) { - BKE_libblock_free(bmain, cu); - RNA_POINTER_INVALIDATE(cu_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Curve '%s' must have zero users to be removed, found %d", - cu->id.name + 2, ID_REAL_USERS(cu)); - } -} static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) { @@ -431,18 +340,6 @@ static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) id_us_min(&mb->id); return mb; } -static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerRNA *mb_ptr) -{ - MetaBall *mb = mb_ptr->data; - if (ID_REAL_USERS(mb) <= 0) { - BKE_libblock_free(bmain, mb); - RNA_POINTER_INVALIDATE(mb_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Metaball '%s' must have zero users to be removed, found %d", - mb->id.name + 2, ID_REAL_USERS(mb)); - } -} static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { @@ -464,18 +361,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char * return font; } -static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *vfont_ptr) -{ - VFont *vfont = vfont_ptr->data; - if (ID_REAL_USERS(vfont) <= 0) { - BKE_libblock_free(bmain, vfont); - RNA_POINTER_INVALIDATE(vfont_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Font '%s' must have zero users to be removed, found %d", - vfont->id.name + 2, ID_REAL_USERS(vfont)); - } -} static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) { @@ -484,18 +369,6 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) id_us_min(&tex->id); return tex; } -static void rna_Main_textures_remove(Main *bmain, ReportList *reports, PointerRNA *tex_ptr) -{ - Tex *tex = tex_ptr->data; - if (ID_REAL_USERS(tex) <= 0) { - BKE_libblock_free(bmain, tex); - RNA_POINTER_INVALIDATE(tex_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Texture '%s' must have zero users to be removed, found %d", - tex->id.name + 2, ID_REAL_USERS(tex)); - } -} static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) { @@ -504,50 +377,17 @@ static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) return brush; } -static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA *brush_ptr) -{ - Brush *brush = brush_ptr->data; - if (ID_REAL_USERS(brush) <= 0) { - BKE_brush_unlink(bmain, brush); - BKE_libblock_free(bmain, brush); - RNA_POINTER_INVALIDATE(brush_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Brush '%s' must have zero users to be removed, found %d", - brush->id.name + 2, ID_REAL_USERS(brush)); - } -} - static World *rna_Main_worlds_new(Main *bmain, const char *name) { World *world = add_world(bmain, name); id_us_min(&world->id); return world; } -static void rna_Main_worlds_remove(Main *bmain, ReportList *reports, PointerRNA *world_ptr) -{ - Group *world = world_ptr->data; - if (ID_REAL_USERS(world) <= 0) { - BKE_libblock_free(bmain, world); - RNA_POINTER_INVALIDATE(world_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "World '%s' must have zero users to be removed, found %d", - world->id.name + 2, ID_REAL_USERS(world)); - } -} static Group *rna_Main_groups_new(Main *bmain, const char *name) { return BKE_group_add(bmain, name); } -static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr) -{ - Group *group = group_ptr->data; - BKE_libblock_unlink(bmain, group, false); - BKE_libblock_free(bmain, group); - RNA_POINTER_INVALIDATE(group_ptr); -} static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) { @@ -555,18 +395,6 @@ static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) id_us_min(&speaker->id); return speaker; } -static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRNA *speaker_ptr) -{ - Speaker *speaker = speaker_ptr->data; - if (ID_REAL_USERS(speaker) <= 0) { - BKE_libblock_free(bmain, speaker); - RNA_POINTER_INVALIDATE(speaker_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Speaker '%s' must have zero users to be removed, found %d", - speaker->id.name + 2, ID_REAL_USERS(speaker)); - } -} static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing) { @@ -582,30 +410,11 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi id_us_min(&sound->id); return sound; } -static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr) -{ - Speaker *sound = sound_ptr->data; - if (ID_REAL_USERS(sound) <= 0) { - BKE_libblock_free(bmain, sound); - RNA_POINTER_INVALIDATE(sound_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d", - sound->id.name + 2, ID_REAL_USERS(sound)); - } -} static Text *rna_Main_texts_new(Main *bmain, const char *name) { return BKE_text_add(bmain, name); } -static void rna_Main_texts_remove(Main *bmain, PointerRNA *text_ptr) -{ - Text *text = text_ptr->data; - BKE_text_unlink(bmain, text); - BKE_libblock_free(bmain, text); - RNA_POINTER_INVALIDATE(text_ptr); -} static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal) { @@ -627,18 +436,6 @@ static bArmature *rna_Main_armatures_new(Main *bmain, const char *name) id_us_min(&arm->id); return arm; } -static void rna_Main_armatures_remove(Main *bmain, ReportList *reports, PointerRNA *arm_ptr) -{ - bArmature *arm = arm_ptr->data; - if (ID_REAL_USERS(arm) <= 0) { - BKE_libblock_free(bmain, arm); - RNA_POINTER_INVALIDATE(arm_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Armature '%s' must have zero users to be removed, found %d", - arm->id.name + 2, ID_REAL_USERS(arm)); - } -} static bAction *rna_Main_actions_new(Main *bmain, const char *name) { @@ -646,18 +443,6 @@ static bAction *rna_Main_actions_new(Main *bmain, const char *name) id_fake_user_clear(&act->id); return act; } -static void rna_Main_actions_remove(Main *bmain, ReportList *reports, PointerRNA *act_ptr) -{ - bAction *act = act_ptr->data; - if (ID_REAL_USERS(act) <= 0) { - BKE_libblock_free(bmain, act); - RNA_POINTER_INVALIDATE(act_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Action '%s' must have zero users to be removed, found %d", - act->id.name + 2, ID_REAL_USERS(act)); - } -} static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) { @@ -665,18 +450,6 @@ static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) id_us_min(&part->id); return part; } -static void rna_Main_particles_remove(Main *bmain, ReportList *reports, PointerRNA *part_ptr) -{ - ParticleSettings *part = part_ptr->data; - if (ID_REAL_USERS(part) <= 0) { - BKE_libblock_free(bmain, part); - RNA_POINTER_INVALIDATE(part_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Particle settings '%s' must have zero users to be removed, found %d", - part->id.name + 2, ID_REAL_USERS(part)); - } -} static Palette *rna_Main_palettes_new(Main *bmain, const char *name) { @@ -684,18 +457,6 @@ static Palette *rna_Main_palettes_new(Main *bmain, const char *name) id_us_min(&palette->id); return (Palette *)palette; } -static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRNA *palette_ptr) -{ - Palette *palette = palette_ptr->data; - if (ID_REAL_USERS(palette) <= 0) { - BKE_libblock_free(bmain, palette); - RNA_POINTER_INVALIDATE(palette_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Palette settings '%s' must have zero users to be removed, found %d", - palette->id.name + 2, ID_REAL_USERS(palette)); - } -} static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { @@ -718,14 +479,6 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons return clip; } -static void rna_Main_movieclips_remove(Main *bmain, PointerRNA *clip_ptr) -{ - MovieClip *clip = clip_ptr->data; - BKE_movieclip_unlink(bmain, clip); - BKE_libblock_free(bmain, clip); - RNA_POINTER_INVALIDATE(clip_ptr); -} - static Mask *rna_Main_mask_new(Main *bmain, const char *name) { Mask *mask; @@ -735,26 +488,6 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name) return mask; } -static void rna_Main_masks_remove(Main *bmain, PointerRNA *mask_ptr) -{ - Mask *mask = mask_ptr->data; - BKE_libblock_free(bmain, mask); - RNA_POINTER_INVALIDATE(mask_ptr); -} - -static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, PointerRNA *gpd_ptr) -{ - bGPdata *gpd = gpd_ptr->data; - if (ID_REAL_USERS(gpd) <= 0) { - BKE_gpencil_free(gpd); - BKE_libblock_free(bmain, gpd); - RNA_POINTER_INVALIDATE(gpd_ptr); - } - else - BKE_reportf(reports, RPT_ERROR, "Grease pencil '%s' must have zero users to be removed, found %d", - gpd->id.name + 2, ID_REAL_USERS(gpd)); -} - static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name) { FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name); @@ -762,17 +495,6 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name return linestyle; } -static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle) -{ - if (ID_REAL_USERS(linestyle) <= 0) - BKE_libblock_free(bmain, linestyle); - else - BKE_reportf(reports, RPT_ERROR, "Line style '%s' must have zero users to be removed, found %d", - linestyle->id.name + 2, ID_REAL_USERS(linestyle)); - - /* XXX python now has invalid pointer? */ -} - /* tag and is_updated functions, all the same */ #define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \ static void rna_Main_##_func_name##_tag(Main *bmain, int value) { \ @@ -855,12 +577,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_cameras_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a camera from the current blendfile"); 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, "", + "Unlink all usages of this camera before deleting it " + "(WARNING: will also delete objects instancing that camera data)"); func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -897,6 +622,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"); func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -931,12 +657,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_objects_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a object from the current blendfile"); RNA_def_function_flag(func, FUNC_USE_REPORTS); 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"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -967,12 +694,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_materials_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a material from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1010,12 +738,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_nodetree_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1068,12 +797,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) "Mesh created from object, remove it if it is only used for export"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile"); 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, "", + "Unlink all usages of this mesh before deleting it " + "(WARNING: will also delete objects instancing that mesh data)"); func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1105,12 +837,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_lamps_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile"); 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, "", + "Unlink all usages of this lamp before deleting it " + "(WARNING: will also delete objects instancing that lamp data)"); func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1220,12 +955,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_images_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove an image from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1256,12 +992,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_lattices_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile"); 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, "", + "Unlink all usages of this lattice before deleting it " + "(WARNING: will also delete objects instancing that lattice data)"); func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1293,12 +1032,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_curves_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a curve from the current blendfile"); 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, "", + "Unlink all usages of this curve before deleting it " + "(WARNING: will also delete objects instancing that curve data)"); func = RNA_def_function(srna, "tag", "rna_Main_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1328,12 +1070,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_metaballs_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile"); 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, "", + "Unlink all usages of this metaball before deleting it " + "(WARNING: will also delete objects instancing that metaball data)"); func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1365,12 +1110,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_fonts_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a font from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1402,12 +1148,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_textures_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a texture from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1438,12 +1185,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_brushes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a brush from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1474,12 +1222,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "world", "World", "", "New world data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_worlds_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a world from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1510,11 +1259,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_groups_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a group from the current blendfile"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); 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"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1545,12 +1296,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_speakers_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile"); 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, "", + "Unlink all usages of this speaker before deleting it " + "(WARNING: will also delete objects instancing that speaker data)"); func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1581,11 +1335,13 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_texts_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a text from the current blendfile"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); 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"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1629,12 +1385,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a sound from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1665,12 +1422,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_armatures_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a armature from the current blendfile"); 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, "", + "Unlink all usages of this armature before deleting it " + "(WARNING: will also delete objects instancing that armature data)"); func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1700,12 +1460,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_actions_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a action from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1735,12 +1496,13 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_particles_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a particle settings instance from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1770,12 +1532,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a palette from the current blendfile"); 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"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1809,12 +1572,13 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_grease_pencil_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile"); 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"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1837,11 +1601,13 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_boolean(func, "value", 0, "Value", ""); RNA_def_property_flag(parm, PROP_REQUIRED); - func = RNA_def_function(srna, "remove", "rna_Main_movieclips_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a movie clip from the current blendfile."); 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"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1887,11 +1653,13 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); /* remove func */ - func = RNA_def_function(srna, "remove", "rna_Main_masks_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a masks from the current blendfile."); 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"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1922,11 +1690,13 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile"); parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED); + 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"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); -- cgit v1.2.3 From 42872656d85ffe95dfe2481264d01263bbb71942 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 25 Jun 2016 17:09:26 +0200 Subject: Cleanup: remove RNA's `ID.destroy()` function. We already have Main's ID lists' `remove()` function, better not do the same thing in two different places! --- source/blender/makesrna/intern/rna_ID.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 92f4d1ac07b..dc6d30854a6 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -336,11 +336,6 @@ static void rna_ID_user_clear(ID *id) id->us = 0; /* don't save */ } -static void rna_ID_delete(ID *id, Main *bmain) -{ - BKE_libblock_delete(bmain, id); -} - static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) { if (GS(id->name) == GS(new_id->name)) { @@ -989,10 +984,6 @@ static void rna_def_ID(BlenderRNA *brna) parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "destroy", "rna_ID_delete"); - RNA_def_function_flag(func, FUNC_USE_MAIN); - RNA_def_function_ui_description(func, "Delete this ID from Blender (WARNING: no undo, do not use it after calling this!)"); - func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear"); RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, " "on reload the data will be removed"); -- cgit v1.2.3 From 1b6cf7a99bef577ce56502681f145474d4729acb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 25 Jun 2016 18:12:23 +0200 Subject: Cleanup: get rid of BKE_text_unlink(), replace by usage of generic BKE_libblock_... API. --- source/blender/blenkernel/BKE_text.h | 1 - source/blender/blenkernel/intern/text.c | 185 --------------------- source/blender/editors/space_text/text_ops.c | 3 +- .../freestyle/intern/system/PythonInterpreter.h | 3 +- 4 files changed, 2 insertions(+), 190 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index b14593f5a56..858feeeab10 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -53,7 +53,6 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta); -void BKE_text_unlink (struct Main *bmain, struct Text *text); void BKE_text_clear (struct Text *text); void BKE_text_write (struct Text *text, const char *str); int BKE_text_file_modified_check(struct Text *text); diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 594f9dffbee..fdc2edba57f 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -498,191 +498,6 @@ Text *BKE_text_copy(Main *bmain, Text *ta) return tan; } -void BKE_text_unlink(Main *bmain, Text *text) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Object *ob; - bController *cont; - bActuator *act; - bConstraint *con; - bNodeTree *ntree; - bNode *node; - Material *mat; - Lamp *la; - Tex *te; - World *wo; - FreestyleLineStyle *linestyle; - Scene *sce; - SceneRenderLayer *srl; - FreestyleModuleConfig *module; - bool update; - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - /* game controllers */ - for (cont = ob->controllers.first; cont; cont = cont->next) { - if (cont->type == CONT_PYTHON) { - bPythonCont *pc; - - pc = cont->data; - if (pc->text == text) pc->text = NULL; - } - } - /* game actuators */ - for (act = ob->actuators.first; act; act = act->next) { - if (act->type == ACT_2DFILTER) { - bTwoDFilterActuator *tfa; - - tfa = act->data; - if (tfa->text == text) tfa->text = NULL; - } - } - - /* pyconstraints */ - update = 0; - - if (ob->type == OB_ARMATURE && ob->pose) { - bPoseChannel *pchan; - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text == text) data->text = NULL; - update = 1; - - } - } - } - } - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text == text) data->text = NULL; - update = 1; - } - } - - if (update) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - - /* nodes */ - for (la = bmain->lamp.first; la; la = la->id.next) { - ntree = la->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { - ntree = linestyle->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (mat = bmain->mat.first; mat; mat = mat->id.next) { - ntree = mat->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (te = bmain->tex.first; te; te = te->id.next) { - ntree = te->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (wo = bmain->world.first; wo; wo = wo->id.next) { - ntree = wo->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - ntree = sce->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - Text *ntext = (Text *)node->id; - if (ntext == text) node->id = NULL; - } - } - - /* Freestyle (while looping over the scene) */ - for (srl = sce->r.layers.first; srl; srl = srl->next) { - for (module = srl->freestyleConfig.modules.first; module; module = module->next) { - if (module->script == text) - module->script = NULL; - } - } - } - - for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - /* text space */ - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_TEXT) { - SpaceText *st = (SpaceText *) sl; - - if (st->text == text) { - st->text = NULL; - st->top = 0; - } - } - } - } - } - - text->id.us = 0; -} - void BKE_text_clear(Text *text) /* called directly from rna */ { int oldstate; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index d404e7aaf15..94ed280f792 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op)) } } - BKE_text_unlink(bmain, text); - BKE_libblock_free(bmain, text); + BKE_libblock_delete(bmain, text); text_drawcache_tag_update(st, 1); WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL); diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h index 5403ec6b13b..0e08af1bac8 100644 --- a/source/blender/freestyle/intern/system/PythonInterpreter.h +++ b/source/blender/freestyle/intern/system/PythonInterpreter.h @@ -84,8 +84,7 @@ public: Text *text = BKE_text_load(&_freestyle_bmain, fn, G.main->name); if (text) { ok = BPY_execute_text(_context, text, reports, false); - BKE_text_unlink(&_freestyle_bmain, text); - BKE_libblock_free(&_freestyle_bmain, text); + BKE_libblock_delete(&_freestyle_bmain, text); } else { BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn); -- cgit v1.2.3 From aff81c6393a56727b4ed5c37f1055b4c2a525677 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 25 Jun 2016 18:35:54 +0200 Subject: Cleanup: Get rid of remaining 'BKE__unlink()' functions, no more used anyway. --- source/blender/blenkernel/BKE_movieclip.h | 1 - source/blender/blenkernel/intern/brush.c | 15 ------- source/blender/blenkernel/intern/mesh.c | 6 --- source/blender/blenkernel/intern/movieclip.c | 67 ---------------------------- 4 files changed, 89 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index afca326c727..3d963ac109c 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -40,7 +40,6 @@ struct MovieClipUser; struct MovieDistortion; void BKE_movieclip_free(struct MovieClip *clip); -void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip); struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name); struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index a3e006a162f..44cacffb71f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -216,21 +216,6 @@ void BKE_brush_free(Brush *brush) BKE_previewimg_free(&(brush->preview)); } -/** - * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc) - * This is only used by RNA, which can remove brushes. - */ -void BKE_brush_unlink(Main *bmain, Brush *brush) -{ - Brush *brush_iter; - - for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) { - if (brush_iter->toggle_brush == brush) { - brush_iter->toggle_brush = NULL; - } - } -} - static void extern_local_brush(Brush *brush) { id_lib_extern((ID *)brush->mtex.tex); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 4e47dfcce74..f82e5cf61b3 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -427,12 +427,6 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) } } -/* Note: unlinking is called when me->id.us is 0, question remains how - * much unlinking of Library data in Mesh should be done... probably - * we need a more generic method, like the expand() functions in - * readfile.c */ - - /** Free (or release) any data used by this mesh (does not free the mesh itself). */ void BKE_mesh_free(Mesh *me) { diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 5f667732b04..f99457a4c26 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1491,73 +1491,6 @@ void BKE_movieclip_free(MovieClip *clip) BKE_tracking_free(&clip->tracking); } -void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Scene *sce; - Object *ob; - - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sc = (SpaceClip *) sl; - - if (sc->clip == clip) - sc->clip = NULL; - } - else if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *) sl; - BGpic *bgpic; - - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if (bgpic->clip == clip) - bgpic->clip = NULL; - } - } - } - } - } - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - if (sce->clip == clip) - sce->clip = NULL; - } - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - bConstraint *con; - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) { - bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - } - } - - FOREACH_NODETREE(bmain, ntree, id) { - BKE_node_tree_unlink_id((ID *)clip, ntree); - } FOREACH_NODETREE_END - - clip->id.us = 0; -} - float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr) { return framenr - (float) clip->start_frame + 1.0f; -- cgit v1.2.3 From 6e193c42cbedbb13a71596b6c8cbb860b7d47cae Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 27 Jun 2016 11:21:03 +1000 Subject: Docs: minor edits to writefile comments --- source/blender/blenloader/intern/writefile.c | 34 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 4fd3e410e63..ef4295ee955 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -29,15 +29,22 @@ */ -/* - * FILEFORMAT: IFF-style structure (but not IFF compatible!) +/** + * + * FILE FORMAT + * =========== + * + * IFF-style structure (but not IFF compatible!) * * start file: + *
  *     BLENDER_V100    12 bytes  (versie 1.00)
  *                     V = big endian, v = little endian
  *                     _ = 4 byte pointer, - = 8 byte pointer
+ * 
* - * datablocks: also see struct BHead + * datablocks: (also see struct #BHead). + *
  *                4 chars
  *                 int,  len data after BHead
  *                 void,  old pointer
@@ -46,29 +53,32 @@
  *     data
  *     ...
  *     ...
+ * 
* * Almost all data in Blender are structures. Each struct saved * gets a BHead header. With BHead the struct can be linked again * and compared with StructDNA . * + * * WRITE + * ===== * * Preferred writing order: (not really a must, but why would you do it random?) * Any case: direct data is ALWAYS after the lib block * * (Local file data) * - for each LibBlock - * - write LibBlock - * - write associated direct data + * - write LibBlock + * - write associated direct data * (External file data) * - per library - * - write library block - * - per LibBlock - * - write the ID of LibBlock - * - write TEST (128x128, blend file preview, optional) - * - write FileGlobal (some global vars) - * - write SDNA - * - write USER if filename is ~/X.XX/config/startup.blend + * - write library block + * - per LibBlock + * - write the ID of LibBlock + * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional). + * - write #GLOB (#FileGlobal struct) (some global vars). + * - write #DNA1 (#SDNA struct) + * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``. */ -- cgit v1.2.3 From c7a6ff0981563295941ffeae2a32ec161a20cf05 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 27 Jun 2016 13:20:56 +1000 Subject: Docs: arg names --- source/blender/blenkernel/intern/bvhutils.c | 4 ++-- source/blender/blenkernel/intern/idcode.c | 10 +++++----- source/blender/blenlib/intern/BLI_filelist.c | 4 ---- source/blender/blenlib/intern/math_geom.c | 2 +- source/blender/blenlib/intern/path_util.c | 2 +- source/blender/bmesh/tools/bmesh_decimate_collapse.c | 3 ++- source/blender/editors/interface/interface.c | 2 +- source/blender/editors/transform/transform_snap_object.c | 2 +- 8 files changed, 13 insertions(+), 16 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 7821946eb6e..e0277c38e61 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -565,7 +565,7 @@ BVHTree *bvhtree_from_mesh_verts( /** * Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!). * \param vert_allocated if true, vert freeing will be done when freeing data. - * \param mask if not null, true elements give which vert to add to BVH tree. + * \param verts_mask if not null, true elements give which vert to add to BVH tree. * \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_verts_ex( @@ -804,7 +804,7 @@ BVHTree *bvhtree_from_mesh_faces( * Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!). * \param vert_allocated if true, vert freeing will be done when freeing data. * \param face_allocated if true, face freeing will be done when freeing data. - * \param mask if not null, true elements give which faces to add to BVH tree. + * \param faces_mask: if not null, true elements give which faces to add to BVH tree. * \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_faces_ex( diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 899ed548783..90b3713e47c 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -124,7 +124,7 @@ static IDType *idtype_from_code(short idcode) /** * Return if the ID code is a valid ID code. * - * \param code The code to check. + * \param idcode: The code to check. * \return Boolean, 0 when invalid. */ bool BKE_idcode_is_valid(short idcode) @@ -135,7 +135,7 @@ bool BKE_idcode_is_valid(short idcode) /** * Return non-zero when an ID type is linkable. * - * \param code The code to check. + * \param idcode: The code to check. * \return Boolean, 0 when non linkable. */ bool BKE_idcode_is_linkable(short idcode) @@ -148,7 +148,7 @@ bool BKE_idcode_is_linkable(short idcode) /** * Convert an idcode into a name. * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the name of * the code. */ @@ -261,7 +261,7 @@ short BKE_idcode_from_idfilter(const int idfilter) /** * Convert an idcode into a name (plural). * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the name of * the code. */ @@ -275,7 +275,7 @@ const char *BKE_idcode_to_name_plural(short idcode) /** * Convert an idcode into its translations' context. * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the i18n context of the code. */ const char *BKE_idcode_to_translation_context(short idcode) diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index 527d9934797..76de52bda66 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -352,8 +352,6 @@ void BLI_filelist_entry_datetime_to_string( /** * Deep-duplicate of a single direntry. - * - * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. */ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src) { @@ -368,8 +366,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s /** * Deep-duplicate of an array of direntries, including the array itself. - * - * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. */ void BLI_filelist_duplicate( struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries) diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 370e8bb0035..124f0c7abb8 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2692,7 +2692,7 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v } /** - * \param r_vi The point \a p projected onto the triangle. + * \param r_isect_co: The point \a p projected onto the triangle. * \return True when \a p is inside the triangle. * \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin. */ diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 2b793841c38..ded10ad7713 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -310,7 +310,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f /** * Remove redundant characters from \a path and optionally make absolute. * - * \param relbase: The path this is relative to, or ignored when NULL. + * \param relabase: The path this is relative to, or ignored when NULL. * \param path: Can be any input, and this function converts it to a regular full path. * Also removes garbage from directory paths, like `/../` or double slashes etc. * diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index b4e8bb06afe..52a0df5b9d1 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -1292,7 +1292,8 @@ static bool bm_decim_edge_collapse( * \param factor face count multiplier [0 - 1] * \param vweights Optional array of vertex aligned weights [0 - 1], * a vertex group is the usual source for this. - * \param axis: Axis of symmetry, -1 to disable mirror decimate. + * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate. + * \param symmetry_eps: Threshold when matching mirror verts. */ void BM_mesh_decimate_collapse( BMesh *bm, diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index fac1267cc62..77990066027 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -4323,7 +4323,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle /** - * \param sfunc, bfunc: both get it as \a arg. + * \param search_func, bfunc: both get it as \a arg. * \param arg: user value, * \param active: when set, button opens with this item visible and selected. */ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index f92f0b33faa..28ad1d93215 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -1642,7 +1642,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( * Given a 2D region value, snap to vert/edge/face. * * \param sctx: Snap context. - * \param mval: Screenspace coordinate. + * \param mval_fl: Screenspace coordinate. * \param dist_px: Maximum distance to snap (in pixels). * \param use_depth: Snap to the closest element, use when using more than one snap type. * \param r_co: hit location. -- cgit v1.2.3 From 538a70c9b640789a67a7f2f19fa53e234443f64c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 27 Jun 2016 12:54:56 +1000 Subject: Cleanup: unnecessary NULL check --- source/blender/blenloader/intern/writefile.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ef4295ee955..7a84eb690cd 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -321,12 +321,6 @@ static WriteData *writedata_new(WriteWrap *ww) { WriteData *wd= MEM_callocN(sizeof(*wd), "writedata"); - /* XXX, see note about this in readfile.c, remove - * once we have an xp lock - zr - */ - - if (wd == NULL) return NULL; - wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false); wd->ww = ww; -- cgit v1.2.3 From 936c176a7137eb58900236e134c3ad5615e30b02 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 27 Jun 2016 14:08:36 +1000 Subject: Fix T48743: Broken menu key accelerators Regression caused by fc96110b --- source/blender/editors/interface/interface_handlers.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index dd823891290..f941993a9e1 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -9813,10 +9813,17 @@ static int ui_handle_menus_recursive( retval = ui_pie_handler(C, event, menu); } else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) { + bool handled = false; + if (listbox) { - retval = ui_handle_list_event(C, event, menu->region, listbox); + int retval_test = ui_handle_list_event(C, event, menu->region, listbox); + if (retval_test != WM_UI_HANDLER_CONTINUE) { + retval = retval_test; + handled = true; + } } - if (retval == WM_UI_HANDLER_CONTINUE) { + + if (handled == false) { retval = ui_handle_menu_event( C, event, menu, level, is_parent_inside, is_parent_menu, is_floating); -- cgit v1.2.3 From 5181f085eb67a8ea2e0c4009adbbe5ae82b61919 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 27 Jun 2016 15:32:52 +1000 Subject: Fix T48733: World background fails in 3d-view Missing from fix for T48555. Unfortunately duplicates code. --- source/blender/gpu/shaders/gpu_shader_vertex.glsl | 6 ++ .../gpu/shaders/gpu_shader_vertex_world.glsl | 68 ++++++++++++++++++++++ 2 files changed, 74 insertions(+) (limited to 'source/blender') diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index 9a6537b4f09..db0068d2f3d 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -14,6 +14,9 @@ varying vec3 varnormal; varying float gl_ClipDistance[6]; #endif + +/* Color, keep in sync with: gpu_shader_vertex_world.glsl */ + float srgb_to_linearrgb(float c) { if (c < 0.04045) @@ -76,6 +79,9 @@ void set_var_from_attr(vec4 attr, int info, out vec4 var) } } +/* end color code */ + + void main() { #ifndef USE_OPENSUBDIV diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl index 9dbcaeb7a32..d45a4b316a8 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl @@ -2,6 +2,74 @@ varying vec3 varposition; varying vec3 varnormal; + +/* Color, keep in sync with: gpu_shader_vertex.glsl */ + +float srgb_to_linearrgb(float c) +{ + if (c < 0.04045) + return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); + else + return pow((c + 0.055) * (1.0 / 1.055), 2.4); +} + +void srgb_to_linearrgb(vec3 col_from, out vec3 col_to) +{ + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); +} + +void srgb_to_linearrgb(vec4 col_from, out vec4 col_to) +{ + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); + col_to.a = col_from.a; +} + +bool is_srgb(int info) +{ +#ifdef USE_NEW_SHADING + return (info == 1)? true: false; +#else + return false; +#endif +} + +void set_var_from_attr(float attr, int info, out float var) +{ + var = attr; +} + +void set_var_from_attr(vec2 attr, int info, out vec2 var) +{ + var = attr; +} + +void set_var_from_attr(vec3 attr, int info, out vec3 var) +{ + if (is_srgb(info)) { + srgb_to_linearrgb(attr, var); + } + else { + var = attr; + } +} + +void set_var_from_attr(vec4 attr, int info, out vec4 var) +{ + if (is_srgb(info)) { + srgb_to_linearrgb(attr, var); + } + else { + var = attr; + } +} + +/* end color code */ + + void main() { /* position does not need to be transformed, we already have it */ -- cgit v1.2.3 From f1253f5d2b710d4a3b3fcb4534007877a136702c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 27 Jun 2016 17:09:52 +1000 Subject: Fix T48717: Modal operators called from Py omit reports from the UI --- source/blender/python/intern/bpy_operator.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source/blender') diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index d6c57f4c302..eaa96e6243c 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -264,6 +264,11 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) if ((reports->flag & RPT_FREE) == 0) { MEM_freeN(reports); } + else { + /* The WM is now responsible for running the modal operator, + * show reports in the info window. */ + reports->flag &= ~RPT_OP_HOLD; + } } WM_operator_properties_free(&ptr); -- cgit v1.2.3 From 5f77266baf20c68befcd2dcffeed67b665f8ccc5 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 27 Jun 2016 10:54:17 +0200 Subject: Fix T48741: File browser back button doesn't work from inside Blend (library) file. Problem was in fact slightly wider, File space was nearly not taking into account library navigation case and its 'virtual' directoris, except in a few places. Add a wrapper around BLI_is_dir that also check for lib paths, and used it in ED_file_change_dir(), such that we now always check path is a valid directory - in the filebrowser context, not filesytem context. ;) --- source/blender/editors/include/ED_fileselect.h | 2 +- source/blender/editors/space_file/file_intern.h | 1 + source/blender/editors/space_file/file_ops.c | 105 ++++++++++++------------ source/blender/editors/space_file/file_utils.c | 17 ++++ source/blender/editors/space_file/filesel.c | 4 +- source/blender/makesrna/intern/rna_space.c | 2 +- 6 files changed, 73 insertions(+), 58 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 80f930a0c30..92acfa6c1d2 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -109,7 +109,7 @@ int ED_file_extension_icon(const char *path); void ED_file_read_bookmarks(void); -void ED_file_change_dir(struct bContext *C, const bool checkdir); +void ED_file_change_dir(struct bContext *C); /* File menu stuff */ diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 71e38f72a7a..a55b18a2212 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art); /* file_utils.c */ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds); +bool file_is_dir(struct SpaceFile *sfile, const char *path); #endif /* __FILE_INTERN_H__ */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d83a7d5ea62..c42ff120102 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) BLI_add_slash(params->dir); } - ED_file_change_dir(C, false); + ED_file_change_dir(C); retval = FILE_SELECT_DIR; } } @@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); BLI_cleanup_dir(G.main->name, params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op) BLI_add_slash(sfile->params->dir); } - ED_file_change_dir(C, false); + ED_file_change_dir(C); } /* opening file - sends events now, so things get handled on windowqueue level */ else if (sfile->op) { @@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) if (sfile->params) { if (BLI_parent_dir(sfile->params->dir)) { BLI_cleanup_dir(G.main->name, sfile->params->dir); - /* if not browsing in .blend file, we still want to check whether the path is a directory */ - if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX]; - if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) { - ED_file_change_dir(C, false); - } - else { - ED_file_change_dir(C, true); - } - } - else { - ED_file_change_dir(C, true); - } + ED_file_change_dir(C); if (sfile->params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ sfile->params->recursion_level = 0; @@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused)) folderlist_popdir(sfile->folders_prev, sfile->params->dir); folderlist_pushdir(sfile->folders_next, sfile->params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused)) // update folders_prev so we can check for it in folderlist_clear_next() folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "open")) { BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN file_expand_directory(C); /* special case, user may have pasted a filepath into the directory */ - if (BLI_is_file(sfile->params->dir)) { - char path[sizeof(sfile->params->dir)]; - BLI_strncpy(path, sfile->params->dir, sizeof(path)); - BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); + if (!file_is_dir(sfile, sfile->params->dir)) { + char tdir[FILE_MAX_LIBEXTRA]; + char *group, *name; + + if (BLI_is_file(sfile->params->dir)) { + char path[sizeof(sfile->params->dir)]; + BLI_strncpy(path, sfile->params->dir, sizeof(path)); + BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, + sizeof(sfile->params->dir), sizeof(sfile->params->file)); + } + else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) { + if (group) { + BLI_path_append(tdir, sizeof(tdir), group); + } + BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir)); + if (name) { + BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file)); + } + else { + sfile->params->file[0] = '\0'; + } + } } BLI_cleanup_dir(G.main->name, sfile->params->dir); - if (BLI_exists(sfile->params->dir)) { + if (file_is_dir(sfile, sfile->params->dir)) { /* if directory exists, enter it immediately */ - ED_file_change_dir(C, true); + ED_file_change_dir(C); /* don't do for now because it selects entire text instead of * placing cursor at the end */ @@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN #endif else { const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); + char tdir[FILE_MAX_LIBEXTRA]; - /* if not, ask to create it and enter if confirmed */ - wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); - PointerRNA ptr; - WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "directory", sfile->params->dir); - RNA_boolean_set(&ptr, "open", true); - - if (lastdir) + /* If we are 'inside' a blend library, we cannot do anything... */ + if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); - - - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); - WM_operator_properties_free(&ptr); + } + else { + /* if not, ask to create it and enter if confirmed */ + wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_string_set(&ptr, "directory", sfile->params->dir); + RNA_boolean_set(&ptr, "open", true); + + if (lastdir) + BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); + } } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg BLI_filename_make_safe(sfile->params->file); if (matches) { - /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */ - sfile->params->file[0] = '\0'; /* replace the pattern (or filename that the user typed in, with the first selected file of the match */ BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file)); @@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg } if (matches == 1) { - BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); /* if directory, open it and empty filename field */ - if (BLI_is_dir(filepath)) { + if (file_is_dir(sfile, filepath)) { BLI_cleanup_dir(G.main->name, filepath); BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); sfile->params->file[0] = '\0'; - ED_file_change_dir(C, true); + ED_file_change_dir(C); UI_textbutton_activate_but(C, but); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); } - else if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX]; - BLI_add_slash(filepath); - if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) { - BLI_cleanup_dir(G.main->name, filepath); - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); - sfile->params->file[0] = '\0'; - ED_file_change_dir(C, false); - UI_textbutton_activate_but(C, but); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } - } } else if (matches > 1) { file_draw_check(C); diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 3c007f25da3..f19e301064d 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -25,6 +25,9 @@ */ #include "BLI_rect.h" +#include "BLI_fileops.h" + +#include "BLO_readfile.h" #include "BKE_context.h" @@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x, ymax - layout->tile_h - layout->tile_border_y, ymax); } + +/* Cannot directly use BLI_is_dir in libloading context... */ +bool file_is_dir(struct SpaceFile *sfile, const char *path) +{ + if (sfile->params->type == FILE_LOADLIB) { + char tdir[FILE_MAX_LIBEXTRA]; + char *name; + if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) { + /* .blend file itself and group are considered as directories, not final datablock names. */ + return name ? false : true; + } + } + return BLI_is_dir(path); +} diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index bf90a4ea170..175d83506c6 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar) return sfile->layout; } -void ED_file_change_dir(bContext *C, const bool checkdir) +void ED_file_change_dir(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); @@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir) sfile->params->filter_search[0] = '\0'; sfile->params->active_file = -1; - if (checkdir && !BLI_is_dir(sfile->params->dir)) { + if (!file_is_dir(sfile, sfile->params->dir)) { BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); /* could return but just refresh the current dir */ } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 4273c29aed8..3586393e738 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1803,7 +1803,7 @@ static void rna_FileBrowser_FSMenu_active_range( static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *UNUSED(ptr)) { - ED_file_change_dir(C, true); + ED_file_change_dir(C); } static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr) -- cgit v1.2.3 From ab921321e1ca6303ee0fa2f2de511b490d9d6427 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 27 Jun 2016 12:38:12 +0200 Subject: Fix (unreported) potential buffer overflow with BLO_library_path_explode() usage. Also added warning to func doc, let's try to avoid this in future (for until we pass string length systematically...). --- source/blender/blenloader/intern/readfile.c | 1 + source/blender/editors/space_file/filelist.c | 9 +++++---- source/blender/imbuf/intern/thumbs.c | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8e69408bfd8..323f0a93e05 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1326,6 +1326,7 @@ bool BLO_has_bfile_extension(const char *str) * * \param path the full path to explode. * \param r_dir the string that'll contain path up to blend file itself ('library' path). + * WARNING! Must be FILE_MAX_LIBEXTRA long (it also stores group and name strings)! * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL. * \param r_name the string that'll contain data's name part of the path, if any. May be NULL. * \return true if path contains a blend file. diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index fc3341bfb92..5e9eb1f9207 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root) static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) { bool is_filtered; - char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name; + char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; BLI_join_dirfile(path, sizeof(path), root, file->relpath); @@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist) if (filelist->max_recursion) { /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless * root path is a blend file. */ - char dir[FILE_MAXDIR]; + char dir[FILE_MAX_LIBEXTRA]; if (!filelist_islibrary(filelist, dir, NULL)) { filelist->filter_data.flags |= FLF_HIDE_LIB_DIR; } @@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir) { - char dir[FILE_MAXDIR]; + char dir[FILE_MAX_LIBEXTRA]; if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) { /* if not a valid library, we need it to be a valid directory! */ BLI_make_exist(r_dir); @@ -2113,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index return 0; } +/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */ bool filelist_islibrary(struct FileList *filelist, char *dir, char **group) { return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL); @@ -2208,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const FileListInternEntry *entry; LinkNode *ln, *names; int i, nnames, idcode = 0, nbr_entries = 0; - char dir[FILE_MAX], *group; + char dir[FILE_MAX_LIBEXTRA], *group; bool ok; struct BlendHandle *libfiledata = NULL; diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 95d061bcb75..3629332a4ac 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -46,6 +46,8 @@ #include "BLO_readfile.h" +#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */ + #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_thumbs.h" @@ -533,7 +535,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source char thumb_path[FILE_MAX]; char thumb_name[40]; char uri[URI_MAX]; - char path_buff[FILE_MAX]; + char path_buff[FILE_MAX_LIBEXTRA]; const char *file_path; const char *path; BLI_stat_t st; -- cgit v1.2.3 From de6064eab174ab29e0845b4d024825e72805ed01 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 27 Jun 2016 15:42:06 +1200 Subject: Ctrl-Shift-C: Made it easier to add constraints between bones in different armatures The Ctrl-Shift-C operator to add constraints between a pair of selected items, for example, between two objects, or between two bones (in the same armature). This commit makes it possible to use this operator to add a constraint where the target is a bone from another object - e.g. to make a deform bone follow the control bone in another armature, or to make an object use a bone as a tracking target. Usage: 1) Ensure you are in Pose Mode, then select the bone to use as the target 2) Shift-Select the other object and/or the bone that's going to get the constraint 3) Ctrl-Shift-C --- source/blender/editors/object/object_constraint.c | 44 +++++++++++++++-------- 1 file changed, 29 insertions(+), 15 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index efd1ebbd51b..2b20d31c60f 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1636,22 +1636,36 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o /* just use the first object we encounter (that isn't the active object) * and which fulfills the criteria for the object-target that we've got */ - if ((ob != obact) && - ((!only_curve) || (ob->type == OB_CURVE)) && - ((!only_mesh) || (ob->type == OB_MESH))) - { - /* set target */ - *tar_ob = ob; - found = 1; - - /* perform some special operations on the target */ - if (only_curve) { - /* Curve-Path option must be enabled for follow-path constraints to be able to work */ - Curve *cu = (Curve *)ob->data; - cu->flag |= CU_PATH; + if (ob != obact) { + /* for armatures in pose mode, look inside the armature for the active bone + * so that we set up cross-armature constraints with less effort + */ + if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && + (!only_curve && !only_mesh)) + { + /* just use the active bone, and assume that it is visible + usable */ + *tar_ob = ob; + *tar_pchan = BKE_pose_channel_active(ob); + found = 1; + + break; + } + else if (((!only_curve) || (ob->type == OB_CURVE)) && + ((!only_mesh) || (ob->type == OB_MESH))) + { + /* set target */ + *tar_ob = ob; + found = 1; + + /* perform some special operations on the target */ + if (only_curve) { + /* Curve-Path option must be enabled for follow-path constraints to be able to work */ + Curve *cu = (Curve *)ob->data; + cu->flag |= CU_PATH; + } + + break; } - - break; } } CTX_DATA_END; -- cgit v1.2.3 From b6483a25f26bad460b4dd2fd13516898f44af6eb Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 27 Jun 2016 15:47:44 +1200 Subject: Code Cleanup: Use bools not shorts --- source/blender/editors/object/object_constraint.c | 36 +++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 2b20d31c60f..9c2806f6f5a 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot) /************************ add constraint operators *********************/ /* get the Object and/or PoseChannel to use as target */ -static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add) +static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) { Object *obact = ED_object_active_context(C); bPoseChannel *pchanact = BKE_pose_channel_active(obact); - short only_curve = 0, only_mesh = 0, only_ob = 0; - short found = 0; + bool only_curve = false, only_mesh = false, only_ob = false; + bool found = false; /* clear tar_ob and tar_pchan fields before use * - assume for now that both always exist... @@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o case CONSTRAINT_TYPE_ROTLIMIT: case CONSTRAINT_TYPE_SIZELIMIT: case CONSTRAINT_TYPE_SAMEVOL: - return 0; + return false; /* restricted target-type constraints -------------- */ /* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */ @@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o case CONSTRAINT_TYPE_CLAMPTO: case CONSTRAINT_TYPE_FOLLOWPATH: case CONSTRAINT_TYPE_SPLINEIK: - only_curve = 1; - only_ob = 1; - add = 0; + only_curve = true; + only_ob = true; + add = false; break; /* mesh only? */ case CONSTRAINT_TYPE_SHRINKWRAP: - only_mesh = 1; - only_ob = 1; - add = 0; + only_mesh = true; + only_ob = true; + add = false; break; /* object only - add here is ok? */ case CONSTRAINT_TYPE_RIGIDBODYJOINT: - only_ob = 1; + only_ob = true; break; } /* if the active Object is Armature, and we can search for bones, do so... */ - if ((obact->type == OB_ARMATURE) && (only_ob == 0)) { + if ((obact->type == OB_ARMATURE) && (only_ob == false)) { /* search in list of selected Pose-Channels for target */ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) { @@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o if (pchan != pchanact) { *tar_ob = obact; *tar_pchan = pchan; - found = 1; + found = true; break; } @@ -1629,7 +1629,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o } /* if not yet found, try selected Objects... */ - if (found == 0) { + if (found == false) { /* search in selected objects context */ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { @@ -1646,7 +1646,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o /* just use the active bone, and assume that it is visible + usable */ *tar_ob = ob; *tar_pchan = BKE_pose_channel_active(ob); - found = 1; + found = true; break; } @@ -1655,7 +1655,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o { /* set target */ *tar_ob = ob; - found = 1; + found = true; /* perform some special operations on the target */ if (only_curve) { @@ -1672,7 +1672,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o } /* if still not found, add a new empty to act as a target (if allowed) */ - if ((found == 0) && (add)) { + if ((found == false) && (add)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Base *base = BASACT, *newbase = NULL; @@ -1706,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o /* make our new target the new object */ *tar_ob = obt; - found = 1; + found = true; } /* return whether there's any target */ -- cgit v1.2.3 From f4e492ad7116f056798ea7b8af22aea01b5e47af Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 27 Jun 2016 19:01:25 +1200 Subject: Partial fix for T48734 The create drivers operator should not use the "Transform Channel" variable type when driving one transform with another on the same object/bone. Otherwise, you end up with a situation which technically results in a bit of a pseudo-dependency cycle. --- source/blender/editors/animation/drivers.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index a82cca9e52a..c24ca1e7027 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -158,7 +158,7 @@ static int add_driver_with_target( ReportList *UNUSED(reports), ID *dst_id, const char dst_path[], int dst_index, ID *src_id, const char src_path[], int src_index, - PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop, + PointerRNA *dst_ptr, PropertyRNA *dst_prop, PointerRNA *src_ptr, PropertyRNA *src_prop, short flag, int driver_type) { @@ -207,11 +207,15 @@ static int add_driver_with_target( /* Create a driver variable for the target * - For transform properties, we want to automatically use "transform channel" instead * (The only issue is with quat rotations vs euler channels...) + * - To avoid problems with transform properties depending on the final transform that they + * control (thus creating pseudo-cycles - see T48734), we don't use transform channels + * when both the source and destinaions are in same places. */ dvar = driver_add_new_variable(driver); if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) && - (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_"))) + (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) && + (src_ptr->data != dst_ptr->data)) { /* Transform Channel */ DriverTarget *dtar; -- cgit v1.2.3 From 34024c7cd8b3e7e90754c80d60ac5cd02de87a85 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 28 Jun 2016 00:25:48 +1200 Subject: FCurve Auto Colours: "XYZ to RGB" works for Quaternions too now The "W" channel will get a yellowish colour (i.e. a blend between the X/R and Y/G axis colours), while the XYZ will behave as they do for other transforms. --- source/blender/editors/animation/keyframing.c | 3 ++ source/blender/editors/space_graph/space_graph.c | 45 ++++++++++++++++++++++++ source/blender/makesdna/DNA_anim_types.h | 5 +-- source/blender/makesrna/intern/rna_fcurve.c | 2 ++ 4 files changed, 53 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 66b3a63c669..0c0f54f0179 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode = FCURVE_COLOR_AUTO_RGB; } + else if (RNA_property_subtype(prop), PROP_QUATERNION) { + fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; + } } /* insert keyframe */ diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index a7284694f64..8ae5932f3fd 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -611,6 +611,51 @@ static void graph_refresh(const bContext *C, ScrArea *sa) } break; } + case FCURVE_COLOR_AUTO_YRGB: + { + /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */ + float *col = fcu->color; + + switch (fcu->array_index) { + case 1: + UI_GetThemeColor3fv(TH_AXIS_X, col); + break; + case 2: + UI_GetThemeColor3fv(TH_AXIS_Y, col); + break; + case 3: + UI_GetThemeColor3fv(TH_AXIS_Z, col); + break; + + case 0: + { + /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */ + float c1[3], c2[3]; + float h1[3], h2[3]; + float hresult[3]; + + /* - get colors (rgb) */ + UI_GetThemeColor3fv(TH_AXIS_X, c1); + UI_GetThemeColor3fv(TH_AXIS_Y, c2); + + /* - perform blending in HSV space (to keep brightness similar) */ + rgb_to_hsv_v(c1, h1); + rgb_to_hsv_v(c2, h2); + + interp_v3_v3v3(hresult, h1, h2, 0.5f); + + /* - convert back to RGB for display */ + hsv_to_rgb_v(hresult, col); + break; + } + + default: + /* 'unknown' color - bluish so as to not conflict with handles */ + col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f; + break; + } + break; + } case FCURVE_COLOR_AUTO_RAINBOW: default: { diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 4c1283452ff..6bd7b3a4999 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -537,8 +537,9 @@ typedef enum eFCurve_Extend { /* curve coloring modes */ typedef enum eFCurve_Coloring { FCURVE_COLOR_AUTO_RAINBOW = 0, /* automatically determine color using rainbow (calculated at drawtime) */ - FCURVE_COLOR_AUTO_RGB, /* automatically determine color using XYZ (array index) <-> RGB */ - FCURVE_COLOR_CUSTOM /* custom color */ + FCURVE_COLOR_AUTO_RGB = 1, /* automatically determine color using XYZ (array index) <-> RGB */ + FCURVE_COLOR_AUTO_YRGB = 3, /* automatically determine color where XYZ <-> RGB, but index(X) != 0 */ + FCURVE_COLOR_CUSTOM = 2, /* custom color */ } eFCurve_Coloring; /* ************************************************ */ diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 1487dfa074e..3043c5452c0 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1844,6 +1844,8 @@ static void rna_def_fcurve(BlenderRNA *brna) "Cycle through the rainbow, trying to give each curve a unique color"}, {FCURVE_COLOR_AUTO_RGB, "AUTO_RGB", 0, "Auto XYZ to RGB", "Use axis colors for transform and color properties, and auto-rainbow for the rest"}, + {FCURVE_COLOR_AUTO_YRGB, "AUTO_YRGB", 0, "Auto WXYZ to YRGB", + "Use axis colors for XYZ parts of transform, and yellow for the 'W' channel"}, {FCURVE_COLOR_CUSTOM, "CUSTOM", 0, "User Defined", "Use custom hand-picked color for F-Curve"}, {0, NULL, 0, NULL, NULL} -- cgit v1.2.3 From e2c7ee773311734450a229051673fbfea61b641a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 27 Jun 2016 15:43:04 +0200 Subject: Fix T48740: User could remap indirect libdata usages from outliner. Remapping indirect usage of IDs is forbidden from user space, this is calling for nice nightmare with libraries handling (and undo crash, among other things). Not sure why I was 'laxist' about indirect usage cases detection like that, for now just consider any ID used by another linked datablock as indirect usage case! Also, added some error/warning reports to Outliner's remap code. --- source/blender/blenkernel/intern/library_remap.c | 7 +++---- source/blender/editors/space_outliner/outliner_edit.c | 11 ++++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 4bde0752ef3..f08315b7896 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -163,15 +163,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), } if (*id_p && (*id_p == old_id)) { + const bool is_indirect = (id->lib != NULL); + const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, * on the other hand since they get reset to lib data on file open/reload it is indirect too... * Edit Mode is also a 'skip direct' case. */ const bool is_obj = (GS(id->name) == ID_OB); const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group)); const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); - /* Note that indirect data from same file as processed ID is **not** considered indirect! */ - const bool is_indirect = ((id->lib != NULL) && (id->lib != old_id->lib)); - const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; @@ -185,7 +184,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), (is_obj_editmode && (((Object *)id)->data == *id_p)) || (skip_indirect && (is_proxy || is_indirect))) { - if (is_never_null || is_proxy || is_obj_editmode) { + if (!is_indirect && (is_never_null || is_proxy || is_obj_editmode)) { id_remap_data->skipped_direct++; } else { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 687869ae727..57d9ff7825b 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -399,13 +399,22 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op) ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")); /* check for invalid states */ - if (soops == NULL) + if (soops == NULL) { return OPERATOR_CANCELLED; + } if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')", + old_id->name, new_id->name); return OPERATOR_CANCELLED; } + if (old_id->lib) { + BKE_reportf(op->reports, RPT_WARNING, + "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped", + old_id->name); + } + BKE_libblock_remap(bmain, old_id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); -- cgit v1.2.3