Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2020-11-19 19:38:48 +0300
committerJacques Lucke <jacques@blender.org>2020-11-19 19:38:48 +0300
commitbb960c85a55b823ee2c76911992043ac8c4eedda (patch)
treec3238b01838796fd128f122cae376fe5335f485c
parenteb25446b9d2df9ca1cde808b12105be502adc4d1 (diff)
parent72a199e148b20c36a63cdf6c6af067c9bcdb3f92 (diff)
Merge branch 'master' into geometry-nodes
-rw-r--r--intern/CMakeLists.txt1
-rw-r--r--intern/atomic/CMakeLists.txt38
-rw-r--r--intern/atomic/tests/atomic_test.cc883
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp15
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h17
-rw-r--r--intern/guardedalloc/intern/mallocn.c52
-rw-r--r--intern/guardedalloc/tests/guardedalloc_alignment_test.cc83
-rw-r--r--intern/guardedalloc/tests/guardedalloc_overflow_test.cc8
-rw-r--r--intern/guardedalloc/tests/guardedalloc_test_base.h26
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h10
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py2
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h25
-rw-r--r--source/blender/blenkernel/BKE_main.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/intern/fluid.c2
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c584
-rw-r--r--source/blender/blenkernel/intern/node.c6
-rw-r--r--source/blender/blenkernel/intern/object.c2
-rw-r--r--source/blender/blenkernel/intern/particle_system.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h4
-rw-r--r--source/blender/compositor/intern/COM_Converter.cpp2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_uv.c12
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c13
-rw-r--r--source/blender/draw/intern/shaders/common_smaa_lib.glsl6
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/armature/pose_group.c2
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c572
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h60
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c22
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c179
-rw-r--r--source/blender/editors/include/ED_gpencil.h18
-rw-r--r--source/blender/editors/include/ED_uvedit.h1
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/interface/interface.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_gpencil_color.c1
-rw-r--r--source/blender/editors/interface/interface_handlers.c13
-rw-r--r--source/blender/editors/interface/interface_icons.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h3
-rw-r--r--source/blender/editors/interface/interface_layout.c2
-rw-r--r--source/blender/editors/interface/interface_panel.c445
-rw-r--r--source/blender/editors/interface/interface_query.c30
-rw-r--r--source/blender/editors/interface/interface_region_popover.c2
-rw-r--r--source/blender/editors/object/object_volume.c2
-rw-r--r--source/blender/editors/physics/physics_pointcache.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c2
-rw-r--r--source/blender/editors/space_graph/graph_edit.c146
-rw-r--r--source/blender/editors/space_node/node_draw.c2
-rw-r--r--source/blender/editors/space_node/node_select.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c1
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c1710
-rw-r--r--source/blender/editors/space_sequencer/sequencer_proxy.c355
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c2
-rw-r--r--source/blender/editors/transform/transform_generics.c5
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.c11
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c26
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.h2
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c1
-rw-r--r--source/blender/gpu/opengl/gl_debug_layer.cc12
-rw-r--r--source/blender/makesdna/DNA_armature_types.h8
-rw-r--r--source/blender/makesdna/DNA_boid_types.h8
-rw-r--r--source/blender/makesdna/DNA_brush_types.h8
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h8
-rw-r--r--source/blender/makesdna/DNA_collection_types.h8
-rw-r--r--source/blender/makesdna/DNA_color_types.h8
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h8
-rw-r--r--source/blender/makesdna/DNA_curve_types.h8
-rw-r--r--source/blender/makesdna/DNA_curveprofile_types.h8
-rw-r--r--source/blender/makesdna/DNA_dynamicpaint_types.h9
-rw-r--r--source/blender/makesdna/DNA_effect_types.h8
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h8
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h8
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h8
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h8
-rw-r--r--source/blender/makesdna/DNA_gpu_types.h8
-rw-r--r--source/blender/makesdna/DNA_hair_types.h8
-rw-r--r--source/blender/makesdna/DNA_image_types.h8
-rw-r--r--source/blender/makesdna/DNA_ipo_types.h8
-rw-r--r--source/blender/makesdna/DNA_key_types.h8
-rw-r--r--source/blender/makesdna/DNA_lattice_types.h8
-rw-r--r--source/blender/makesdna/DNA_light_types.h8
-rw-r--r--source/blender/makesdna/DNA_linestyle_types.h8
-rw-r--r--source/blender/makesdna/DNA_mask_types.h8
-rw-r--r--source/blender/makesdna/DNA_material_types.h8
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_meta_types.h8
-rw-r--r--source/blender/makesdna/DNA_nla_types.h8
-rw-r--r--source/blender/makesdna/DNA_node_types.h8
-rw-r--r--source/blender/makesdna/DNA_object_enums.h8
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h8
-rw-r--r--source/blender/makesdna/DNA_packedFile_types.h8
-rw-r--r--source/blender/makesdna/DNA_particle_types.h8
-rw-r--r--source/blender/makesdna/DNA_pointcloud_types.h8
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h8
-rw-r--r--source/blender/makesdna/DNA_scene_types.h2
-rw-r--r--source/blender/makesdna/DNA_screen_types.h8
-rw-r--r--source/blender/makesdna/DNA_sdna_types.h8
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h8
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h8
-rw-r--r--source/blender/makesdna/DNA_sound_types.h8
-rw-r--r--source/blender/makesdna/DNA_space_types.h8
-rw-r--r--source/blender/makesdna/DNA_speaker_types.h8
-rw-r--r--source/blender/makesdna/DNA_text_types.h8
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h8
-rw-r--r--source/blender/makesdna/DNA_vec_types.h8
-rw-r--r--source/blender/makesdna/DNA_vfont_types.h8
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h8
-rw-r--r--source/blender/makesdna/DNA_view3d_enums.h8
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h8
-rw-r--r--source/blender/makesdna/DNA_volume_types.h8
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h8
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h8
-rw-r--r--source/blender/makesdna/DNA_world_types.h8
-rw-r--r--source/blender/makesdna/DNA_xr_types.h8
-rw-r--r--source/blender/makesdna/intern/dna_utils.h8
-rw-r--r--source/blender/makesrna/intern/rna_define.c7
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c1
-rw-r--r--source/blender/makesrna/intern/rna_rna.c1
-rw-r--r--source/blender/makesrna/intern/rna_scene.c10
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c4
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c5
-rw-r--r--source/blender/nodes/intern/node_common.c4
-rw-r--r--source/blender/python/bmesh/bmesh_py_utils.c3
-rw-r--r--source/blender/python/intern/bpy_rna.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c2
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c23
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h20
-rw-r--r--source/blender/sequencer/intern/strip_edit.c125
139 files changed, 3898 insertions, 2243 deletions
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index c1792a312b2..dbd939e64b7 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -19,6 +19,7 @@
# ***** END GPL LICENSE BLOCK *****
# add_subdirectory(atomic) # header only
+add_subdirectory(atomic)
add_subdirectory(clog)
add_subdirectory(ghost)
add_subdirectory(guardedalloc)
diff --git a/intern/atomic/CMakeLists.txt b/intern/atomic/CMakeLists.txt
new file mode 100644
index 00000000000..afcafc4c8ab
--- /dev/null
+++ b/intern/atomic/CMakeLists.txt
@@ -0,0 +1,38 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2020, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+)
+
+set(INC_SYS
+)
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ tests/atomic_test.cc
+ )
+ set(TEST_INC
+ )
+ set(TEST_LIB
+ )
+ include(GTestTesting)
+ blender_add_test_executable(atomic "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
+endif()
diff --git a/intern/atomic/tests/atomic_test.cc b/intern/atomic/tests/atomic_test.cc
new file mode 100644
index 00000000000..f52422d0d30
--- /dev/null
+++ b/intern/atomic/tests/atomic_test.cc
@@ -0,0 +1,883 @@
+/* Apache License, Version 2.0 */
+
+#include <limits>
+
+#include "atomic_ops.h"
+#include "testing/testing.h"
+
+#ifdef __GNUC__
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */
+# pragma GCC diagnostic error "-Wsign-compare"
+# endif
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 408
+# pragma GCC diagnostic error "-Wsign-conversion"
+# endif
+#endif
+
+/* NOTE: it is suboptimal to duplicate same check as in API, but this check is
+ * planned to be removed, making it so 64bit intrinsics are available on 32bit
+ * platforms. */
+#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
+
+/* -------------------------------------------------------------------- */
+/** \name 64 bit unsigned int atomics
+ * \{ */
+
+TEST(atomic, atomic_add_and_fetch_uint64)
+{
+ {
+ uint64_t value = 1;
+ EXPECT_EQ(atomic_add_and_fetch_uint64(&value, 2), 3);
+ EXPECT_EQ(value, 3);
+ }
+
+ {
+ uint64_t value = 0x1020304050607080;
+ EXPECT_EQ(atomic_add_and_fetch_uint64(&value, 0x0807060504030201), 0x1827364554637281);
+ EXPECT_EQ(value, 0x1827364554637281);
+ }
+
+ {
+ uint64_t value = 0x9020304050607080;
+ EXPECT_EQ(atomic_add_and_fetch_uint64(&value, 0x0807060504030201), 0x9827364554637281);
+ EXPECT_EQ(value, 0x9827364554637281);
+ }
+}
+
+TEST(atomic, atomic_sub_and_fetch_uint64)
+{
+ {
+ uint64_t value = 3;
+ EXPECT_EQ(atomic_sub_and_fetch_uint64(&value, 2), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ {
+ uint64_t value = 0x1827364554637281;
+ EXPECT_EQ(atomic_sub_and_fetch_uint64(&value, 0x0807060504030201), 0x1020304050607080);
+ EXPECT_EQ(value, 0x1020304050607080);
+ }
+
+ {
+ uint64_t value = 0x9827364554637281;
+ EXPECT_EQ(atomic_sub_and_fetch_uint64(&value, 0x0807060504030201), 0x9020304050607080);
+ EXPECT_EQ(value, 0x9020304050607080);
+ }
+
+ {
+ uint64_t value = 1;
+ EXPECT_EQ(atomic_sub_and_fetch_uint64(&value, 2), 0xffffffffffffffff);
+ EXPECT_EQ(value, 0xffffffffffffffff);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_add_uint64)
+{
+ {
+ uint64_t value = 1;
+ EXPECT_EQ(atomic_fetch_and_add_uint64(&value, 2), 1);
+ EXPECT_EQ(value, 3);
+ }
+
+ {
+ uint64_t value = 0x1020304050607080;
+ EXPECT_EQ(atomic_fetch_and_add_uint64(&value, 0x0807060504030201), 0x1020304050607080);
+ EXPECT_EQ(value, 0x1827364554637281);
+ }
+
+ {
+ uint64_t value = 0x9020304050607080;
+ EXPECT_EQ(atomic_fetch_and_add_uint64(&value, 0x0807060504030201), 0x9020304050607080);
+ EXPECT_EQ(value, 0x9827364554637281);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_sub_uint64)
+{
+ {
+ uint64_t value = 3;
+ EXPECT_EQ(atomic_fetch_and_sub_uint64(&value, 2), 3);
+ EXPECT_EQ(value, 1);
+ }
+
+ {
+ uint64_t value = 0x1827364554637281;
+ EXPECT_EQ(atomic_fetch_and_sub_uint64(&value, 0x0807060504030201), 0x1827364554637281);
+ EXPECT_EQ(value, 0x1020304050607080);
+ }
+
+ {
+ uint64_t value = 0x9827364554637281;
+ EXPECT_EQ(atomic_fetch_and_sub_uint64(&value, 0x0807060504030201), 0x9827364554637281);
+ EXPECT_EQ(value, 0x9020304050607080);
+ }
+
+ {
+ uint64_t value = 1;
+ EXPECT_EQ(atomic_fetch_and_sub_uint64(&value, 2), 1);
+ EXPECT_EQ(value, 0xffffffffffffffff);
+ }
+}
+
+TEST(atomic, atomic_cas_uint64)
+{
+ {
+ uint64_t value = 1;
+ EXPECT_EQ(atomic_cas_uint64(&value, 1, 2), 1);
+ EXPECT_EQ(value, 2);
+ }
+
+ {
+ uint64_t value = 1;
+ EXPECT_EQ(atomic_cas_uint64(&value, 2, 3), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ {
+ uint64_t value = 0x1234567890abcdef;
+ EXPECT_EQ(atomic_cas_uint64(&value, 0x1234567890abcdef, 0xfedcba0987654321),
+ 0x1234567890abcdef);
+ EXPECT_EQ(value, 0xfedcba0987654321);
+ }
+
+ {
+ uint64_t value = 0x1234567890abcdef;
+ EXPECT_EQ(atomic_cas_uint64(&value, 0xdeadbeefefefefef, 0xfedcba0987654321),
+ 0x1234567890abcdef);
+ EXPECT_EQ(value, 0x1234567890abcdef);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name 64 bit signed int atomics
+ * \{ */
+
+TEST(atomic, atomic_add_and_fetch_int64)
+{
+ {
+ int64_t value = 1;
+ EXPECT_EQ(atomic_add_and_fetch_int64(&value, 2), 3);
+ EXPECT_EQ(value, 3);
+ }
+
+ {
+ int64_t value = 0x1020304050607080;
+ EXPECT_EQ(atomic_add_and_fetch_int64(&value, 0x0807060504030201), 0x1827364554637281);
+ EXPECT_EQ(value, 0x1827364554637281);
+ }
+
+ {
+ int64_t value = -0x1020304050607080;
+ EXPECT_EQ(atomic_add_and_fetch_int64(&value, -0x0807060504030201), -0x1827364554637281);
+ EXPECT_EQ(value, -0x1827364554637281);
+ }
+}
+
+TEST(atomic, atomic_sub_and_fetch_int64)
+{
+ {
+ int64_t value = 3;
+ EXPECT_EQ(atomic_sub_and_fetch_int64(&value, 2), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ {
+ int64_t value = 0x1827364554637281;
+ EXPECT_EQ(atomic_sub_and_fetch_int64(&value, 0x0807060504030201), 0x1020304050607080);
+ EXPECT_EQ(value, 0x1020304050607080);
+ }
+
+ {
+ int64_t value = -0x1827364554637281;
+ EXPECT_EQ(atomic_sub_and_fetch_int64(&value, -0x0807060504030201), -0x1020304050607080);
+ EXPECT_EQ(value, -0x1020304050607080);
+ }
+
+ {
+ int64_t value = 1;
+ EXPECT_EQ(atomic_sub_and_fetch_int64(&value, 2), -1);
+ EXPECT_EQ(value, -1);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_add_int64)
+{
+ {
+ int64_t value = 1;
+ EXPECT_EQ(atomic_fetch_and_add_int64(&value, 2), 1);
+ EXPECT_EQ(value, 3);
+ }
+
+ {
+ int64_t value = 0x1020304050607080;
+ EXPECT_EQ(atomic_fetch_and_add_int64(&value, 0x0807060504030201), 0x1020304050607080);
+ EXPECT_EQ(value, 0x1827364554637281);
+ }
+
+ {
+ int64_t value = -0x1020304050607080;
+ EXPECT_EQ(atomic_fetch_and_add_int64(&value, -0x0807060504030201), -0x1020304050607080);
+ EXPECT_EQ(value, -0x1827364554637281);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_sub_int64)
+{
+ {
+ int64_t value = 3;
+ EXPECT_EQ(atomic_fetch_and_sub_int64(&value, 2), 3);
+ EXPECT_EQ(value, 1);
+ }
+
+ {
+ int64_t value = 0x1827364554637281;
+ EXPECT_EQ(atomic_fetch_and_sub_int64(&value, 0x0807060504030201), 0x1827364554637281);
+ EXPECT_EQ(value, 0x1020304050607080);
+ }
+
+ {
+ int64_t value = -0x1827364554637281;
+ EXPECT_EQ(atomic_fetch_and_sub_int64(&value, -0x0807060504030201), -0x1827364554637281);
+ EXPECT_EQ(value, -0x1020304050607080);
+ }
+
+ {
+ int64_t value = 1;
+ EXPECT_EQ(atomic_fetch_and_sub_int64(&value, 2), 1);
+ EXPECT_EQ(value, -1);
+ }
+}
+
+TEST(atomic, atomic_cas_int64)
+{
+ {
+ int64_t value = 1;
+ EXPECT_EQ(atomic_cas_int64(&value, 1, 2), 1);
+ EXPECT_EQ(value, 2);
+ }
+
+ {
+ int64_t value = 1;
+ EXPECT_EQ(atomic_cas_int64(&value, 2, 3), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ // 0xfedcba0987654321 is -0x012345f6789abcdf
+ // 0xdeadbeefefefefef is -0x2152411010101011
+
+ {
+ int64_t value = 0x1234567890abcdef;
+ EXPECT_EQ(atomic_cas_int64(&value, 0x1234567890abcdef, -0x012345f6789abcdf),
+ 0x1234567890abcdef);
+ EXPECT_EQ(value, -0x012345f6789abcdf);
+ }
+
+ {
+ int64_t value = 0x1234567890abcdef;
+ EXPECT_EQ(atomic_cas_int64(&value, 0x2152411010101011, -0x012345f6789abcdf),
+ 0x1234567890abcdef);
+ EXPECT_EQ(value, 0x1234567890abcdef);
+ }
+}
+
+/** \} */
+
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name 32 bit unsigned int atomics
+ * \{ */
+
+TEST(atomic, atomic_add_and_fetch_uint32)
+{
+ {
+ uint32_t value = 1;
+ EXPECT_EQ(atomic_add_and_fetch_uint32(&value, 2), 3);
+ EXPECT_EQ(value, 3);
+ }
+
+ {
+ uint32_t value = 0x10203040;
+ EXPECT_EQ(atomic_add_and_fetch_uint32(&value, 0x04030201), 0x14233241);
+ EXPECT_EQ(value, 0x14233241);
+ }
+
+ {
+ uint32_t value = 0x90203040;
+ EXPECT_EQ(atomic_add_and_fetch_uint32(&value, 0x04030201), 0x94233241);
+ EXPECT_EQ(value, 0x94233241);
+ }
+}
+
+TEST(atomic, atomic_sub_and_fetch_uint32)
+{
+ {
+ uint32_t value = 3;
+ EXPECT_EQ(atomic_sub_and_fetch_uint32(&value, 2), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ {
+ uint32_t value = 0x14233241;
+ EXPECT_EQ(atomic_sub_and_fetch_uint32(&value, 0x04030201), 0x10203040);
+ EXPECT_EQ(value, 0x10203040);
+ }
+
+ {
+ uint32_t value = 0x94233241;
+ EXPECT_EQ(atomic_sub_and_fetch_uint32(&value, 0x04030201), 0x90203040);
+ EXPECT_EQ(value, 0x90203040);
+ }
+
+ {
+ uint32_t value = 1;
+ EXPECT_EQ(atomic_sub_and_fetch_uint32(&value, 2), 0xffffffff);
+ EXPECT_EQ(value, 0xffffffff);
+ }
+}
+
+TEST(atomic, atomic_cas_uint32)
+{
+ {
+ uint32_t value = 1;
+ EXPECT_EQ(atomic_cas_uint32(&value, 1, 2), 1);
+ EXPECT_EQ(value, 2);
+ }
+
+ {
+ uint32_t value = 1;
+ EXPECT_EQ(atomic_cas_uint32(&value, 2, 3), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ {
+ uint32_t value = 0x12345678;
+ EXPECT_EQ(atomic_cas_uint32(&value, 0x12345678, 0x87654321), 0x12345678);
+ EXPECT_EQ(value, 0x87654321);
+ }
+
+ {
+ uint32_t value = 0x12345678;
+ EXPECT_EQ(atomic_cas_uint32(&value, 0xdeadbeef, 0x87654321), 0x12345678);
+ EXPECT_EQ(value, 0x12345678);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_add_uint32)
+{
+ {
+ uint32_t value = 1;
+ EXPECT_EQ(atomic_fetch_and_add_uint32(&value, 2), 1);
+ EXPECT_EQ(value, 3);
+ }
+
+ {
+ uint32_t value = 0x10203040;
+ EXPECT_EQ(atomic_fetch_and_add_uint32(&value, 0x04030201), 0x10203040);
+ EXPECT_EQ(value, 0x14233241);
+ }
+
+ {
+ uint32_t value = 0x90203040;
+ EXPECT_EQ(atomic_fetch_and_add_uint32(&value, 0x04030201), 0x90203040);
+ EXPECT_EQ(value, 0x94233241);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_or_uint32)
+{
+ {
+ uint32_t value = 12;
+ EXPECT_EQ(atomic_fetch_and_or_uint32(&value, 5), 12);
+ EXPECT_EQ(value, 13);
+ }
+
+ {
+ uint32_t value = 0x12345678;
+ EXPECT_EQ(atomic_fetch_and_or_uint32(&value, 0x87654321), 0x12345678);
+ EXPECT_EQ(value, 0x97755779);
+ }
+
+ {
+ uint32_t value = 0x92345678;
+ EXPECT_EQ(atomic_fetch_and_or_uint32(&value, 0x87654321), 0x92345678);
+ EXPECT_EQ(value, 0x97755779);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_and_uint32)
+{
+ {
+ uint32_t value = 12;
+ EXPECT_EQ(atomic_fetch_and_and_uint32(&value, 5), 12);
+ EXPECT_EQ(value, 4);
+ }
+
+ {
+ uint32_t value = 0x12345678;
+ EXPECT_EQ(atomic_fetch_and_and_uint32(&value, 0x87654321), 0x12345678);
+ EXPECT_EQ(value, 0x02244220);
+ }
+
+ {
+ uint32_t value = 0x92345678;
+ EXPECT_EQ(atomic_fetch_and_and_uint32(&value, 0x87654321), 0x92345678);
+ EXPECT_EQ(value, 0x82244220);
+ }
+}
+
+/** \} */
+
+/** \name 32 bit signed int atomics
+ * \{ */
+
+TEST(atomic, atomic_add_and_fetch_int32)
+{
+ {
+ int32_t value = 1;
+ EXPECT_EQ(atomic_add_and_fetch_int32(&value, 2), 3);
+ EXPECT_EQ(value, 3);
+ }
+
+ {
+ int32_t value = 0x10203040;
+ EXPECT_EQ(atomic_add_and_fetch_int32(&value, 0x04030201), 0x14233241);
+ EXPECT_EQ(value, 0x14233241);
+ }
+
+ {
+ int32_t value = -0x10203040;
+ EXPECT_EQ(atomic_add_and_fetch_int32(&value, -0x04030201), -0x14233241);
+ EXPECT_EQ(value, -0x14233241);
+ }
+}
+
+TEST(atomic, atomic_sub_and_fetch_int32)
+{
+ {
+ int32_t value = 3;
+ EXPECT_EQ(atomic_sub_and_fetch_int32(&value, 2), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ {
+ int32_t value = 0x14233241;
+ EXPECT_EQ(atomic_sub_and_fetch_int32(&value, 0x04030201), 0x10203040);
+ EXPECT_EQ(value, 0x10203040);
+ }
+
+ {
+ int32_t value = -0x14233241;
+ EXPECT_EQ(atomic_sub_and_fetch_int32(&value, -0x04030201), -0x10203040);
+ EXPECT_EQ(value, -0x10203040);
+ }
+
+ {
+ int32_t value = 1;
+ EXPECT_EQ(atomic_sub_and_fetch_int32(&value, 2), 0xffffffff);
+ EXPECT_EQ(value, 0xffffffff);
+ }
+}
+
+TEST(atomic, atomic_cas_int32)
+{
+ {
+ int32_t value = 1;
+ EXPECT_EQ(atomic_cas_int32(&value, 1, 2), 1);
+ EXPECT_EQ(value, 2);
+ }
+
+ {
+ int32_t value = 1;
+ EXPECT_EQ(atomic_cas_int32(&value, 2, 3), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ // 0x87654321 is -0x789abcdf
+ // 0xdeadbeef is -0x21524111
+
+ {
+ int32_t value = 0x12345678;
+ EXPECT_EQ(atomic_cas_int32(&value, 0x12345678, -0x789abcdf), 0x12345678);
+ EXPECT_EQ(value, -0x789abcdf);
+ }
+
+ {
+ int32_t value = 0x12345678;
+ EXPECT_EQ(atomic_cas_int32(&value, -0x21524111, -0x789abcdf), 0x12345678);
+ EXPECT_EQ(value, 0x12345678);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_add_int32)
+{
+ {
+ int32_t value = 1;
+ EXPECT_EQ(atomic_fetch_and_add_int32(&value, 2), 1);
+ EXPECT_EQ(value, 3);
+ }
+
+ {
+ int32_t value = 0x10203040;
+ EXPECT_EQ(atomic_fetch_and_add_int32(&value, 0x04030201), 0x10203040);
+ EXPECT_EQ(value, 0x14233241);
+ }
+
+ {
+ int32_t value = -0x10203040;
+ EXPECT_EQ(atomic_fetch_and_add_int32(&value, -0x04030201), -0x10203040);
+ EXPECT_EQ(value, -0x14233241);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_or_int32)
+{
+ {
+ int32_t value = 12;
+ EXPECT_EQ(atomic_fetch_and_or_int32(&value, 5), 12);
+ EXPECT_EQ(value, 13);
+ }
+
+ // 0x87654321 is -0x789abcdf
+
+ {
+ int32_t value = 0x12345678;
+ EXPECT_EQ(atomic_fetch_and_or_int32(&value, -0x789abcdf), 0x12345678);
+ EXPECT_EQ(value, 0x97755779);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_and_int32)
+{
+ {
+ int32_t value = 12;
+ EXPECT_EQ(atomic_fetch_and_and_int32(&value, 5), 12);
+ EXPECT_EQ(value, 4);
+ }
+
+ {
+ int32_t value = 0x12345678;
+ EXPECT_EQ(atomic_fetch_and_and_int32(&value, -0x789abcdf), 0x12345678);
+ EXPECT_EQ(value, 0x02244220);
+ }
+}
+
+/** \} */
+
+/** \name 8 bit unsigned int atomics
+ * \{ */
+
+TEST(atomic, atomic_fetch_and_or_uint8)
+{
+ {
+ uint8_t value = 12;
+ EXPECT_EQ(atomic_fetch_and_or_uint8(&value, 5), 12);
+ EXPECT_EQ(value, 13);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_and_uint8)
+{
+ {
+ uint8_t value = 12;
+ EXPECT_EQ(atomic_fetch_and_and_uint8(&value, 5), 12);
+ EXPECT_EQ(value, 4);
+ }
+}
+
+/** \} */
+
+/** \name 8 bit signed int atomics
+ * \{ */
+
+TEST(atomic, atomic_fetch_and_or_int8)
+{
+ {
+ int8_t value = 12;
+ EXPECT_EQ(atomic_fetch_and_or_int8(&value, 5), 12);
+ EXPECT_EQ(value, 13);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_and_int8)
+{
+ {
+ int8_t value = 12;
+ EXPECT_EQ(atomic_fetch_and_and_int8(&value, 5), 12);
+ EXPECT_EQ(value, 4);
+ }
+}
+
+/** \} */
+
+/** \name char aliases
+ * \{ */
+
+TEST(atomic, atomic_fetch_and_or_char)
+{
+ {
+ char value = 12;
+ EXPECT_EQ(atomic_fetch_and_or_char(&value, 5), 12);
+ EXPECT_EQ(value, 13);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_and_char)
+{
+ {
+ char value = 12;
+ EXPECT_EQ(atomic_fetch_and_and_char(&value, 5), 12);
+ EXPECT_EQ(value, 4);
+ }
+}
+
+/** \} */
+
+/** \name size_t aliases
+ * \{ */
+
+TEST(atomic, atomic_add_and_fetch_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 1;
+ EXPECT_EQ(atomic_add_and_fetch_z(&value, 2), 3);
+ EXPECT_EQ(value, 3);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = size_t_max - 10;
+ EXPECT_EQ(atomic_add_and_fetch_z(&value, 2), size_t_max - 8);
+ EXPECT_EQ(value, size_t_max - 8);
+ }
+}
+
+TEST(atomic, atomic_sub_and_fetch_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 3;
+ EXPECT_EQ(atomic_sub_and_fetch_z(&value, 2), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = size_t_max - 10;
+ EXPECT_EQ(atomic_sub_and_fetch_z(&value, 2), size_t_max - 12);
+ EXPECT_EQ(value, size_t_max - 12);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_add_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 1;
+ EXPECT_EQ(atomic_fetch_and_add_z(&value, 2), 1);
+ EXPECT_EQ(value, 3);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = size_t_max - 10;
+ EXPECT_EQ(atomic_fetch_and_add_z(&value, 2), size_t_max - 10);
+ EXPECT_EQ(value, size_t_max - 8);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_sub_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 3;
+ EXPECT_EQ(atomic_fetch_and_sub_z(&value, 2), 3);
+ EXPECT_EQ(value, 1);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = size_t_max - 10;
+ EXPECT_EQ(atomic_fetch_and_sub_z(&value, 2), size_t_max - 10);
+ EXPECT_EQ(value, size_t_max - 12);
+ }
+}
+
+TEST(atomic, atomic_cas_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 1;
+ EXPECT_EQ(atomic_cas_z(&value, 1, 2), 1);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = 1;
+ EXPECT_EQ(atomic_cas_z(&value, 1, size_t_max), 1);
+ EXPECT_EQ(value, size_t_max);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_update_max_z)
+{
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+
+ size_t value = 12;
+
+ EXPECT_EQ(atomic_fetch_and_update_max_z(&value, 8), 12);
+ EXPECT_EQ(value, 12);
+
+ EXPECT_EQ(atomic_fetch_and_update_max_z(&value, 24), 12);
+ EXPECT_EQ(value, 24);
+
+ EXPECT_EQ(atomic_fetch_and_update_max_z(&value, size_t_max), 24);
+ EXPECT_EQ(value, size_t_max);
+}
+
+/** \} */
+
+/** \name unsigned int aliases
+ * \{ */
+
+TEST(atomic, atomic_add_and_fetch_u)
+{
+ /* Make sure alias is implemented. */
+ {
+ unsigned int value = 1;
+ EXPECT_EQ(atomic_add_and_fetch_u(&value, 2), 3);
+ EXPECT_EQ(value, 3);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const unsigned int uint_max = std::numeric_limits<unsigned int>::max();
+ unsigned int value = uint_max - 10;
+ EXPECT_EQ(atomic_add_and_fetch_u(&value, 2), uint_max - 8);
+ EXPECT_EQ(value, uint_max - 8);
+ }
+}
+
+TEST(atomic, atomic_sub_and_fetch_u)
+{
+ /* Make sure alias is implemented. */
+ {
+ unsigned int value = 3;
+ EXPECT_EQ(atomic_sub_and_fetch_u(&value, 2), 1);
+ EXPECT_EQ(value, 1);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const unsigned int uint_max = std::numeric_limits<unsigned int>::max();
+ unsigned int value = uint_max - 10;
+ EXPECT_EQ(atomic_sub_and_fetch_u(&value, 2), uint_max - 12);
+ EXPECT_EQ(value, uint_max - 12);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_add_u)
+{
+ /* Make sure alias is implemented. */
+ {
+ unsigned int value = 1;
+ EXPECT_EQ(atomic_fetch_and_add_u(&value, 2), 1);
+ EXPECT_EQ(value, 3);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const unsigned int uint_max = std::numeric_limits<unsigned int>::max();
+ unsigned int value = uint_max - 10;
+ EXPECT_EQ(atomic_fetch_and_add_u(&value, 2), uint_max - 10);
+ EXPECT_EQ(value, uint_max - 8);
+ }
+}
+
+TEST(atomic, atomic_fetch_and_sub_u)
+{
+ /* Make sure alias is implemented. */
+ {
+ unsigned int value = 3;
+ EXPECT_EQ(atomic_fetch_and_sub_u(&value, 2), 3);
+ EXPECT_EQ(value, 1);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const unsigned int uint_max = std::numeric_limits<unsigned int>::max();
+ unsigned int value = uint_max - 10;
+ EXPECT_EQ(atomic_fetch_and_sub_u(&value, 2), uint_max - 10);
+ EXPECT_EQ(value, uint_max - 12);
+ }
+}
+
+TEST(atomic, atomic_cas_u)
+{
+ /* Make sure alias is implemented. */
+ {
+ unsigned int value = 1;
+ EXPECT_EQ(atomic_cas_u(&value, 1, 2), 1);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const unsigned int uint_max = std::numeric_limits<unsigned int>::max();
+ unsigned int value = 1;
+ EXPECT_EQ(atomic_cas_u(&value, 1, uint_max), 1);
+ EXPECT_EQ(value, uint_max);
+ }
+}
+
+/** \} */
+
+/** \name pointer aliases
+ * \{ */
+
+#define INT_AS_PTR(a) reinterpret_cast<void *>((a))
+
+TEST(atomic, atomic_cas_ptr)
+{
+ {
+ void *value = INT_AS_PTR(0x7f);
+ EXPECT_EQ(atomic_cas_ptr(&value, INT_AS_PTR(0x7f), INT_AS_PTR(0xef)), INT_AS_PTR(0x7f));
+ EXPECT_EQ(value, INT_AS_PTR(0xef));
+ }
+}
+
+#undef INT_AS_PTR
+
+/** \} */
+
+/** \name floating point atomics
+ * \{ */
+
+TEST(atomic, atomic_cas_float)
+{
+ {
+ float value = 1.234f;
+ EXPECT_EQ(atomic_cas_float(&value, 1.234f, 2.71f), 1.234f);
+ EXPECT_EQ(value, 2.71f);
+ }
+}
+
+TEST(atomic, atomic_add_and_fetch_fl)
+{
+ {
+ float value = 1.23f;
+ EXPECT_NEAR(atomic_add_and_fetch_fl(&value, 2.71f), 3.94f, 1e-8f);
+ EXPECT_NEAR(value, 3.94f, 1e-8f);
+ }
+}
+
+/** \} */
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 5904a72b186..af02663985d 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -1401,16 +1401,16 @@ void GHOST_WindowWin32::updatePendingWintabEvents()
if (!(m_wintab.packetsGet && m_wintab.context)) {
return;
}
- GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
auto &pendingEvents = m_wintab.pendingEvents;
/* Clear outdated events from queue. */
- GHOST_TUns64 currTime = system->getMilliSeconds();
- GHOST_TUns64 timeout = 300;
+ DWORD currTime = ::GetTickCount();
+ DWORD millisTimeout = 500;
while (!pendingEvents.empty()) {
- GHOST_TUns64 pktTime = system->millisSinceStart(pendingEvents.front().pkTime);
- if (currTime - pktTime > timeout) {
+ DWORD pkTime = pendingEvents.front().pkTime;
+
+ if (currTime > pkTime + millisTimeout) {
pendingEvents.pop();
}
else {
@@ -1426,8 +1426,9 @@ void GHOST_WindowWin32::updatePendingWintabEvents()
/* Don't queue outdated packets, such events can include packets that occurred before the current
* window lost and regained focus. */
for (; i < numPackets; i++) {
- GHOST_TUns64 pktTime = system->millisSinceStart(m_wintab.pkts[i].pkTime);
- if (currTime - pktTime < timeout) {
+ DWORD pkTime = m_wintab.pkts[i].pkTime;
+
+ if (currTime < pkTime + millisTimeout) {
break;
}
}
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index f12eb0ac340..0f30f7bd1a5 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -226,7 +226,22 @@ void MEM_use_memleak_detection(bool enabled);
* tests. */
void MEM_enable_fail_on_memleak(void);
-/* Switch allocator to slower but fully guarded mode. */
+/* Switch allocator to fast mode, with less tracking.
+ *
+ * Use in the production code where performance is the priority, and exact details about allocation
+ * is not. This allocator keeps track of number of allocation and amount of allocated bytes, but it
+ * does not track of names of allocated blocks.
+ *
+ * NOTE: The switch between allocator types can only happen before any allocation did happen. */
+void MEM_use_lockfree_allocator(void);
+
+/* Switch allocator to slow fully guarded mode.
+ *
+ * Use for debug purposes. This allocator contains lock section around every allocator call, which
+ * makes it slow. What is gained with this is the ability to have list of allocated blocks (in an
+ * addition to the trackign of number of allocations and amount of allocated bytes).
+ *
+ * NOTE: The switch between allocator types can only happen before any allocation did happen. */
void MEM_use_guarded_allocator(void);
#ifdef __cplusplus
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index e85f8eb03ed..f0dd29a0b9e 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -36,6 +36,7 @@
const char *malloc_conf = "background_thread:true,dirty_decay_ms:4000";
#endif
+/* NOTE: Keep in sync with MEM_use_lockfree_allocator(). */
size_t (*MEM_allocN_len)(const void *vmemh) = MEM_lockfree_allocN_len;
void (*MEM_freeN)(void *vmemh) = MEM_lockfree_freeN;
void *(*MEM_dupallocN)(const void *vmemh) = MEM_lockfree_dupallocN;
@@ -95,8 +96,59 @@ void aligned_free(void *ptr)
#endif
}
+/* Perform assert checks on allocator type change.
+ *
+ * Helps catching issues (in debug build) caused by an unintended allocator type change when there
+ * are allocation happenned. */
+static void assert_for_allocator_change(void)
+{
+ /* NOTE: Assume that there is no "sticky" internal state which would make switching allocator
+ * type after all allocations are freed unsafe. In fact, it should be safe to change allocator
+ * type after all blocks has been freed: some regression tests do rely on this property of
+ * allocators. */
+ assert(MEM_get_memory_blocks_in_use() == 0);
+}
+
+void MEM_use_lockfree_allocator(void)
+{
+ /* NOTE: Keep in sync with static initialization of the variables. */
+
+ /* TODO(sergey): Find a way to de-duplicate the logic. Maybe by requiring an explicit call
+ * to guarded allocator initialization at an application startup. */
+
+ assert_for_allocator_change();
+
+ MEM_allocN_len = MEM_lockfree_allocN_len;
+ MEM_freeN = MEM_lockfree_freeN;
+ MEM_dupallocN = MEM_lockfree_dupallocN;
+ MEM_reallocN_id = MEM_lockfree_reallocN_id;
+ MEM_recallocN_id = MEM_lockfree_recallocN_id;
+ MEM_callocN = MEM_lockfree_callocN;
+ MEM_calloc_arrayN = MEM_lockfree_calloc_arrayN;
+ MEM_mallocN = MEM_lockfree_mallocN;
+ MEM_malloc_arrayN = MEM_lockfree_malloc_arrayN;
+ MEM_mallocN_aligned = MEM_lockfree_mallocN_aligned;
+ MEM_printmemlist_pydict = MEM_lockfree_printmemlist_pydict;
+ MEM_printmemlist = MEM_lockfree_printmemlist;
+ MEM_callbackmemlist = MEM_lockfree_callbackmemlist;
+ MEM_printmemlist_stats = MEM_lockfree_printmemlist_stats;
+ MEM_set_error_callback = MEM_lockfree_set_error_callback;
+ MEM_consistency_check = MEM_lockfree_consistency_check;
+ MEM_set_memory_debug = MEM_lockfree_set_memory_debug;
+ MEM_get_memory_in_use = MEM_lockfree_get_memory_in_use;
+ MEM_get_memory_blocks_in_use = MEM_lockfree_get_memory_blocks_in_use;
+ MEM_reset_peak_memory = MEM_lockfree_reset_peak_memory;
+ MEM_get_peak_memory = MEM_lockfree_get_peak_memory;
+
+#ifndef NDEBUG
+ MEM_name_ptr = MEM_lockfree_name_ptr;
+#endif
+}
+
void MEM_use_guarded_allocator(void)
{
+ assert_for_allocator_change();
+
MEM_allocN_len = MEM_guarded_allocN_len;
MEM_freeN = MEM_guarded_freeN;
MEM_dupallocN = MEM_guarded_dupallocN;
diff --git a/intern/guardedalloc/tests/guardedalloc_alignment_test.cc b/intern/guardedalloc/tests/guardedalloc_alignment_test.cc
index 4c676c6cc76..cd19a43695c 100644
--- a/intern/guardedalloc/tests/guardedalloc_alignment_test.cc
+++ b/intern/guardedalloc/tests/guardedalloc_alignment_test.cc
@@ -5,6 +5,7 @@
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
+#include "guardedalloc_test_base.h"
#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ((size_t)ptr % align, 0)
@@ -32,90 +33,26 @@ void DoBasicAlignmentChecks(const int alignment)
} // namespace
-TEST(guardedalloc, LockfreeAlignedAlloc1)
+TEST_F(LockFreeAllocatorTest, MEM_mallocN_aligned)
{
DoBasicAlignmentChecks(1);
-}
-
-TEST(guardedalloc, GuardedAlignedAlloc1)
-{
- MEM_use_guarded_allocator();
- DoBasicAlignmentChecks(1);
-}
-
-TEST(guardedalloc, LockfreeAlignedAlloc2)
-{
DoBasicAlignmentChecks(2);
-}
-
-TEST(guardedalloc, GuardedAlignedAlloc2)
-{
- MEM_use_guarded_allocator();
- DoBasicAlignmentChecks(2);
-}
-
-TEST(guardedalloc, LockfreeAlignedAlloc4)
-{
DoBasicAlignmentChecks(4);
-}
-
-TEST(guardedalloc, GuardedAlignedAlloc4)
-{
- MEM_use_guarded_allocator();
- DoBasicAlignmentChecks(4);
-}
-
-TEST(guardedalloc, LockfreeAlignedAlloc8)
-{
DoBasicAlignmentChecks(8);
-}
-
-TEST(guardedalloc, GuardedAlignedAlloc8)
-{
- MEM_use_guarded_allocator();
- DoBasicAlignmentChecks(8);
-}
-
-TEST(guardedalloc, LockfreeAlignedAlloc16)
-{
DoBasicAlignmentChecks(16);
-}
-
-TEST(guardedalloc, GuardedAlignedAlloc16)
-{
- MEM_use_guarded_allocator();
- DoBasicAlignmentChecks(16);
-}
-
-TEST(guardedalloc, LockfreeAlignedAlloc32)
-{
DoBasicAlignmentChecks(32);
-}
-
-TEST(guardedalloc, GuardedAlignedAlloc32)
-{
- MEM_use_guarded_allocator();
- DoBasicAlignmentChecks(32);
-}
-
-TEST(guardedalloc, LockfreeAlignedAlloc256)
-{
DoBasicAlignmentChecks(256);
-}
-
-TEST(guardedalloc, GuardedAlignedAlloc256)
-{
- MEM_use_guarded_allocator();
- DoBasicAlignmentChecks(256);
-}
-
-TEST(guardedalloc, LockfreeAlignedAlloc512)
-{
DoBasicAlignmentChecks(512);
}
-TEST(guardedalloc, GuardedAlignedAlloc512)
+TEST_F(GuardedAllocatorTest, MEM_mallocN_aligned)
{
- MEM_use_guarded_allocator();
+ DoBasicAlignmentChecks(1);
+ DoBasicAlignmentChecks(2);
+ DoBasicAlignmentChecks(4);
+ DoBasicAlignmentChecks(8);
+ DoBasicAlignmentChecks(16);
+ DoBasicAlignmentChecks(32);
+ DoBasicAlignmentChecks(256);
DoBasicAlignmentChecks(512);
}
diff --git a/intern/guardedalloc/tests/guardedalloc_overflow_test.cc b/intern/guardedalloc/tests/guardedalloc_overflow_test.cc
index efbfc171fff..1424005e181 100644
--- a/intern/guardedalloc/tests/guardedalloc_overflow_test.cc
+++ b/intern/guardedalloc/tests/guardedalloc_overflow_test.cc
@@ -4,6 +4,8 @@
#include "MEM_guardedalloc.h"
+#include "guardedalloc_test_base.h"
+
/* We expect to abort on integer overflow, to prevent possible exploits. */
#if defined(__GNUC__) && !defined(__clang__)
@@ -31,7 +33,7 @@ void CallocArray(size_t len, size_t size)
} // namespace
-TEST(guardedalloc, LockfreeIntegerOverflow)
+TEST_F(LockFreeAllocatorTest, LockfreeIntegerOverflow)
{
MallocArray(1, SIZE_MAX);
CallocArray(SIZE_MAX, 1);
@@ -44,10 +46,8 @@ TEST(guardedalloc, LockfreeIntegerOverflow)
EXPECT_EXIT(CallocArray(SIZE_MAX, SIZE_MAX), ABORT_PREDICATE, "");
}
-TEST(guardedalloc, GuardedIntegerOverflow)
+TEST_F(GuardedAllocatorTest, GuardedIntegerOverflow)
{
- MEM_use_guarded_allocator();
-
MallocArray(1, SIZE_MAX);
CallocArray(SIZE_MAX, 1);
MallocArray(SIZE_MAX / 2, 2);
diff --git a/intern/guardedalloc/tests/guardedalloc_test_base.h b/intern/guardedalloc/tests/guardedalloc_test_base.h
new file mode 100644
index 00000000000..c56cb9abe29
--- /dev/null
+++ b/intern/guardedalloc/tests/guardedalloc_test_base.h
@@ -0,0 +1,26 @@
+/* Apache License, Version 2.0 */
+
+#ifndef __GUARDEDALLOC_TEST_UTIL_H__
+#define __GUARDEDALLOC_TEST_UTIL_H__
+
+#include "testing/testing.h"
+
+#include "MEM_guardedalloc.h"
+
+class LockFreeAllocatorTest : public ::testing::Test {
+ protected:
+ virtual void SetUp()
+ {
+ MEM_use_lockfree_allocator();
+ }
+};
+
+class GuardedAllocatorTest : public ::testing::Test {
+ protected:
+ virtual void SetUp()
+ {
+ MEM_use_guarded_allocator();
+ }
+};
+
+#endif // __GUARDEDALLOC_TEST_UTIL_H__
diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h
index 1f22f4b3d21..3aedef4a284 100644
--- a/intern/mantaflow/intern/strings/fluid_script.h
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -118,6 +118,7 @@ timePerFrame_s$ID$ = $TIME_PER_FRAME$\n\
# In Blender fluid.c: frame_length = DT_DEFAULT * (25.0 / fps) * time_scale\n\
# with DT_DEFAULT = 0.1\n\
frameLength_s$ID$ = $FRAME_LENGTH$\n\
+frameLengthUnscaled_s$ID$ = frameLength_s$ID$ / timeScale_s$ID$\n\
frameLengthRaw_s$ID$ = 0.1 * 25 # dt = 0.1 at 25 fps\n\
\n\
dt0_s$ID$ = $DT$\n\
@@ -144,9 +145,15 @@ mantaMsg('1 Blender length unit is ' + str(ratioResToBLength_s$ID$) + ' Mantaflo
ratioBTimeToTimestep_s$ID$ = float(1) / float(frameLengthRaw_s$ID$) # the time within 1 blender time unit, see also fluid.c\n\
mantaMsg('1 Blender time unit is ' + str(ratioBTimeToTimestep_s$ID$) + ' Mantaflow time units long.')\n\
\n\
+ratioFrameToFramelength_s$ID$ = float(1) / float(frameLengthUnscaled_s$ID$ ) # the time within 1 frame\n\
+mantaMsg('frame / frameLength is ' + str(ratioFrameToFramelength_s$ID$) + ' Mantaflow time units long.')\n\
+\n\
scaleAcceleration_s$ID$ = ratioResToBLength_s$ID$ * (ratioBTimeToTimestep_s$ID$**2)# [meters/btime^2] to [cells/timestep^2] (btime: sec, min, or h, ...)\n\
mantaMsg('scaleAcceleration is ' + str(scaleAcceleration_s$ID$))\n\
\n\
+scaleSpeedFrames_s$ID$ = ratioResToBLength_s$ID$ * ratioFrameToFramelength_s$ID$ # [blength/frame] to [cells/frameLength]\n\
+mantaMsg('scaleSpeed is ' + str(scaleSpeedFrames_s$ID$))\n\
+\n\
gravity_s$ID$ *= scaleAcceleration_s$ID$ # scale from world acceleration to cell based acceleration\n\
\n\
# OpenVDB options\n\
@@ -376,6 +383,9 @@ def fluid_pre_step_$ID$():\n\
interpolateMACGrid(source=guidevel_sg$ID$, target=velT_s$ID$)\n\
velT_s$ID$.multConst(vec3(gamma_sg$ID$))\n\
\n\
+ x_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
+ y_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
+ z_force_s$ID$.multConst(scaleSpeedFrames_s$ID$)\n\
copyRealToVec3(sourceX=x_force_s$ID$, sourceY=y_force_s$ID$, sourceZ=z_force_s$ID$, target=forces_s$ID$)\n\
\n\
# If obstacle has velocity, i.e. is a moving obstacle, switch to dynamic preconditioner\n\
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 2e888dbd141..6ad1d99dadc 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -657,6 +657,8 @@ class VIEW3D_HT_header(Header):
sub.prop(tool_settings, "use_gpencil_weight_data_add", text="", icon='WPAINT_HLT')
sub.separator(factor=0.4)
sub.prop(tool_settings, "use_gpencil_draw_additive", text="", icon='FREEZE')
+ sub.separator(factor=0.4)
+ sub.prop(tool_settings, "use_gpencil_automerge_strokes", text="")
# Select mode for Editing
if gpd.use_stroke_edit_mode:
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 8c0103d10e6..293d55a6015 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -1364,7 +1364,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_settings(Panel, View3DPanel, GreasePen
row_mat.template_ID(gp_settings, "material", live_icon=True)
else:
row_mat.template_ID(context.active_object, "active_material", live_icon=True)
- row_mat.enabled = False # will otherwise allow to change material in active slot
+ row_mat.enabled = False # will otherwise allow changing material in active slot
row.prop(gp_settings, "use_material_pin", text="")
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 6917a62053c..b107a6e72af 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -37,6 +37,7 @@ struct bGPDlayer;
struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
+struct bGPDcurve;
/* Object boundbox. */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);
@@ -115,6 +116,21 @@ bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps, const float dist, const
bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps,
const int index_from,
const int index_to);
+struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd,
+ struct bGPDframe *gpf,
+ struct bGPDstroke *gps,
+ struct bGPDstroke *next_stroke,
+ int tag_flags,
+ bool select,
+ int limit);
+void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd,
+ struct bGPDframe *gpf,
+ struct bGPDstroke *gps,
+ struct bGPDstroke *next_stroke,
+ struct bGPDcurve *gpc,
+ int tag_flags);
+
+void BKE_gpencil_stroke_flip(struct bGPDstroke *gps);
bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
@@ -123,9 +139,18 @@ bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist);
float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
+float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
+ const int start_index,
+ const int end_index,
+ bool use_3d);
void BKE_gpencil_stroke_set_random_color(struct bGPDstroke *gps);
+void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a,
+ struct bGPDstroke *gps_b,
+ const bool leave_gaps,
+ const bool fit_thickness);
+
bool BKE_gpencil_convert_mesh(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index a0535c91905..8106607572b 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -99,7 +99,7 @@ typedef struct Main {
*/
char is_memfile_undo_flush_needed;
/**
- * Indicates that next memfile undo step should not allow to re-use old bmain when re-read, but
+ * Indicates that next memfile undo step should not allow reusing old bmain when re-read, but
* instead do a complete full re-read/update from stored memfile.
*/
char use_memfile_full_barrier;
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index d2cb3891d4f..975500d164d 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -512,7 +512,7 @@ void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree);
struct bNodeType *nodeTypeFind(const char *idname);
void nodeRegisterType(struct bNodeType *ntype);
void nodeUnregisterType(struct bNodeType *ntype);
-bool nodeIsRegistered(struct bNode *node);
+bool nodeTypeUndefined(struct bNode *node);
struct GHashIterator *nodeTypeGetIterator(void);
/* helper macros for iterating over node types */
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 30bf84ae6e1..434456a922e 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -3202,6 +3202,8 @@ static void update_effectors_task_cb(void *__restrict userdata,
mul_v3_fl(retvel, mag);
/* Copy computed force to fluid solver forces. */
+ mul_v3_fl(retvel, 0.2f); /* Factor from 0e6820cc5d62. */
+ CLAMP3(retvel, -1.0f, 1.0f); /* Restrict forces to +-1 interval. */
data->force_x[index] = retvel[0];
data->force_y[index] = retvel[1];
data->force_z[index] = retvel[2];
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index d2cfb36cb15..fc74439fd76 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -1345,6 +1345,34 @@ float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
return total_length;
}
+/** Calculate grease pencil stroke length between points. */
+float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
+ const int start_index,
+ const int end_index,
+ bool use_3d)
+{
+ if (!gps->points || gps->totpoints < 2 || end_index <= start_index) {
+ return 0.0f;
+ }
+
+ int index = MAX2(start_index, 0) + 1;
+ int last_index = MIN2(end_index, gps->totpoints - 1) + 1;
+
+ float *last_pt = &gps->points[index - 1].x;
+ float total_length = 0.0f;
+ for (int i = index; i < last_index; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (use_3d) {
+ total_length += len_v3v3(&pt->x, last_pt);
+ }
+ else {
+ total_length += len_v2v2(&pt->x, last_pt);
+ }
+ last_pt = &pt->x;
+ }
+ return total_length;
+}
+
/**
* Trim stroke to the first intersection or loop.
* \param gps: Stroke data
@@ -2640,4 +2668,560 @@ void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
copy_v4_v4(pt->vert_color, color);
}
}
+
+/* Flip stroke. */
+void BKE_gpencil_stroke_flip(bGPDstroke *gps)
+{
+ int end = gps->totpoints - 1;
+
+ for (int i = 0; i < gps->totpoints / 2; i++) {
+ bGPDspoint *point, *point2;
+ bGPDspoint pt;
+
+ /* save first point */
+ point = &gps->points[i];
+ pt.x = point->x;
+ pt.y = point->y;
+ pt.z = point->z;
+ pt.flag = point->flag;
+ pt.pressure = point->pressure;
+ pt.strength = point->strength;
+ pt.time = point->time;
+ copy_v4_v4(pt.vert_color, point->vert_color);
+
+ /* replace first point with last point */
+ point2 = &gps->points[end];
+ point->x = point2->x;
+ point->y = point2->y;
+ point->z = point2->z;
+ point->flag = point2->flag;
+ point->pressure = point2->pressure;
+ point->strength = point2->strength;
+ point->time = point2->time;
+ copy_v4_v4(point->vert_color, point2->vert_color);
+
+ /* replace last point with first saved before */
+ point = &gps->points[end];
+ point->x = pt.x;
+ point->y = pt.y;
+ point->z = pt.z;
+ point->flag = pt.flag;
+ point->pressure = pt.pressure;
+ point->strength = pt.strength;
+ point->time = pt.time;
+ copy_v4_v4(point->vert_color, pt.vert_color);
+
+ end--;
+ }
+}
+
+/* Temp data for storing information about an "island" of points
+ * that should be kept when splitting up a stroke. Used in:
+ * gpencil_stroke_delete_tagged_points()
+ */
+typedef struct tGPDeleteIsland {
+ int start_idx;
+ int end_idx;
+} tGPDeleteIsland;
+
+static void gpencil_stroke_join_islands(bGPdata *gpd,
+ bGPDframe *gpf,
+ bGPDstroke *gps_first,
+ bGPDstroke *gps_last)
+{
+ bGPDspoint *pt = NULL;
+ bGPDspoint *pt_final = NULL;
+ const int totpoints = gps_first->totpoints + gps_last->totpoints;
+
+ /* create new stroke */
+ bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false, true);
+
+ join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
+ join_stroke->totpoints = totpoints;
+ join_stroke->flag &= ~GP_STROKE_CYCLIC;
+
+ /* copy points (last before) */
+ int e1 = 0;
+ int e2 = 0;
+ float delta = 0.0f;
+
+ for (int i = 0; i < totpoints; i++) {
+ pt_final = &join_stroke->points[i];
+ if (i < gps_last->totpoints) {
+ pt = &gps_last->points[e1];
+ e1++;
+ }
+ else {
+ pt = &gps_first->points[e2];
+ e2++;
+ }
+
+ /* copy current point */
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = delta;
+ pt_final->flag = pt->flag;
+ copy_v4_v4(pt_final->vert_color, pt->vert_color);
+
+ /* retiming with fixed time interval (we cannot determine real time) */
+ delta += 0.01f;
+ }
+
+ /* Copy over vertex weight data (if available) */
+ if ((gps_first->dvert != NULL) || (gps_last->dvert != NULL)) {
+ join_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * totpoints, __func__);
+ MDeformVert *dvert_src = NULL;
+ MDeformVert *dvert_dst = NULL;
+
+ /* Copy weights (last before)*/
+ e1 = 0;
+ e2 = 0;
+ for (int i = 0; i < totpoints; i++) {
+ dvert_dst = &join_stroke->dvert[i];
+ dvert_src = NULL;
+ if (i < gps_last->totpoints) {
+ if (gps_last->dvert) {
+ dvert_src = &gps_last->dvert[e1];
+ e1++;
+ }
+ }
+ else {
+ if (gps_first->dvert) {
+ dvert_src = &gps_first->dvert[e2];
+ e2++;
+ }
+ }
+
+ if ((dvert_src) && (dvert_src->dw)) {
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ }
+ }
+ }
+
+ /* add new stroke at head */
+ BLI_addhead(&gpf->strokes, join_stroke);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, join_stroke);
+
+ /* remove first stroke */
+ BLI_remlink(&gpf->strokes, gps_first);
+ BKE_gpencil_free_stroke(gps_first);
+
+ /* remove last stroke */
+ BLI_remlink(&gpf->strokes, gps_last);
+ BKE_gpencil_free_stroke(gps_last);
+}
+
+/* Split the given stroke into several new strokes, partitioning
+ * it based on whether the stroke points have a particular flag
+ * is set (e.g. "GP_SPOINT_SELECT" in most cases, but not always)
+ *
+ * The algorithm used here is as follows:
+ * 1) We firstly identify the number of "islands" of non-tagged points
+ * which will all end up being in new strokes.
+ * - In the most extreme case (i.e. every other vert is a 1-vert island),
+ * we have at most n / 2 islands
+ * - Once we start having larger islands than that, the number required
+ * becomes much less
+ * 2) Each island gets converted to a new stroke
+ * If the number of points is <= limit, the stroke is deleted
+ */
+bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ bGPDstroke *next_stroke,
+ int tag_flags,
+ bool select,
+ int limit)
+{
+ tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2,
+ "gp_point_islands");
+ bool in_island = false;
+ int num_islands = 0;
+
+ bGPDstroke *new_stroke = NULL;
+ bGPDstroke *gps_first = NULL;
+ const bool is_cyclic = (bool)(gps->flag & GP_STROKE_CYCLIC);
+
+ /* First Pass: Identify start/end of islands */
+ bGPDspoint *pt = gps->points;
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & tag_flags) {
+ /* selected - stop accumulating to island */
+ in_island = false;
+ }
+ else {
+ /* unselected - start of a new island? */
+ int idx;
+
+ if (in_island) {
+ /* extend existing island */
+ idx = num_islands - 1;
+ islands[idx].end_idx = i;
+ }
+ else {
+ /* start of new island */
+ in_island = true;
+ num_islands++;
+
+ idx = num_islands - 1;
+ islands[idx].start_idx = islands[idx].end_idx = i;
+ }
+ }
+ }
+
+ /* Watch out for special case where No islands = All points selected = Delete Stroke only */
+ if (num_islands) {
+ /* There are islands, so create a series of new strokes,
+ * adding them before the "next" stroke. */
+ int idx;
+
+ /* Create each new stroke... */
+ for (idx = 0; idx < num_islands; idx++) {
+ tGPDeleteIsland *island = &islands[idx];
+ new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true);
+
+ /* if cyclic and first stroke, save to join later */
+ if ((is_cyclic) && (gps_first == NULL)) {
+ gps_first = new_stroke;
+ }
+
+ new_stroke->flag &= ~GP_STROKE_CYCLIC;
+
+ /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
+ new_stroke->totpoints = island->end_idx - island->start_idx + 1;
+
+ /* Copy over the relevant point data */
+ new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints,
+ "gp delete stroke fragment");
+ memcpy(new_stroke->points,
+ gps->points + island->start_idx,
+ sizeof(bGPDspoint) * new_stroke->totpoints);
+
+ /* Copy over vertex weight data (if available) */
+ if (gps->dvert != NULL) {
+ /* Copy over the relevant vertex-weight points */
+ new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints,
+ "gp delete stroke fragment weight");
+ memcpy(new_stroke->dvert,
+ gps->dvert + island->start_idx,
+ sizeof(MDeformVert) * new_stroke->totpoints);
+
+ /* Copy weights */
+ int e = island->start_idx;
+ for (int i = 0; i < new_stroke->totpoints; i++) {
+ MDeformVert *dvert_src = &gps->dvert[e];
+ MDeformVert *dvert_dst = &new_stroke->dvert[i];
+ if (dvert_src->dw) {
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ }
+ e++;
+ }
+ }
+ /* Each island corresponds to a new stroke.
+ * We must adjust the timings of these new strokes:
+ *
+ * Each point's timing data is a delta from stroke's inittime, so as we erase some points
+ * from the start of the stroke, we have to offset this inittime and all remaining points'
+ * delta values. This way we get a new stroke with exactly the same timing as if user had
+ * started drawing from the first non-removed point.
+ */
+ {
+ bGPDspoint *pts;
+ float delta = gps->points[island->start_idx].time;
+ int j;
+
+ new_stroke->inittime += (double)delta;
+
+ pts = new_stroke->points;
+ for (j = 0; j < new_stroke->totpoints; j++, pts++) {
+ pts->time -= delta;
+ /* set flag for select again later */
+ if (select == true) {
+ pts->flag &= ~GP_SPOINT_SELECT;
+ pts->flag |= GP_SPOINT_TAG;
+ }
+ }
+ }
+
+ /* Add new stroke to the frame or delete if below limit */
+ if ((limit > 0) && (new_stroke->totpoints <= limit)) {
+ BKE_gpencil_free_stroke(new_stroke);
+ }
+ else {
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
+
+ if (next_stroke) {
+ BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
+ }
+ }
+ /* if cyclic, need to join last stroke with first stroke */
+ if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) {
+ gpencil_stroke_join_islands(gpd, gpf, gps_first, new_stroke);
+ }
+ }
+
+ /* free islands */
+ MEM_freeN(islands);
+
+ /* Delete the old stroke */
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+
+ return new_stroke;
+}
+
+void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ bGPDstroke *next_stroke,
+ bGPDcurve *gpc,
+ int tag_flags)
+{
+ if (gpc == NULL) {
+ return;
+ }
+ const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
+ const int idx_last = gpc->tot_curve_points - 1;
+ bGPDstroke *gps_first = NULL;
+ bGPDstroke *gps_last = NULL;
+
+ int idx_start = 0;
+ int idx_end = 0;
+ bool prev_selected = gpc->curve_points[0].flag & tag_flags;
+ for (int i = 1; i < gpc->tot_curve_points; i++) {
+ bool selected = gpc->curve_points[i].flag & tag_flags;
+ if (prev_selected == true && selected == false) {
+ idx_start = i;
+ }
+ /* Island ends if the current point is selected or if we reached the end of the stroke */
+ if ((prev_selected == false && selected == true) || (selected == false && i == idx_last)) {
+
+ idx_end = selected ? i - 1 : i;
+ int island_length = idx_end - idx_start + 1;
+
+ /* If an island has only a single curve point, there is no curve segment, so skip island */
+ if (island_length == 1) {
+ if (is_cyclic) {
+ if (idx_start > 0 && idx_end < idx_last) {
+ prev_selected = selected;
+ continue;
+ }
+ }
+ else {
+ prev_selected = selected;
+ continue;
+ }
+ }
+
+ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, false, false);
+ new_stroke->points = NULL;
+ new_stroke->flag &= ~GP_STROKE_CYCLIC;
+ new_stroke->editcurve = BKE_gpencil_stroke_editcurve_new(island_length);
+
+ if (gps_first == NULL) {
+ gps_first = new_stroke;
+ }
+
+ bGPDcurve *new_gpc = new_stroke->editcurve;
+ memcpy(new_gpc->curve_points,
+ gpc->curve_points + idx_start,
+ sizeof(bGPDcurve_point) * island_length);
+
+ BKE_gpencil_editcurve_recalculate_handles(new_stroke);
+ new_stroke->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
+
+ if (next_stroke) {
+ BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
+
+ gps_last = new_stroke;
+ }
+ prev_selected = selected;
+ }
+
+ /* join first and last stroke if cyclic */
+ if (is_cyclic && gps_first != NULL && gps_last != NULL && gps_first != gps_last) {
+ bGPDcurve *gpc_first = gps_first->editcurve;
+ bGPDcurve *gpc_last = gps_last->editcurve;
+ int first_tot_points = gpc_first->tot_curve_points;
+ int old_tot_points = gpc_last->tot_curve_points;
+
+ gpc_last->tot_curve_points = first_tot_points + old_tot_points;
+ gpc_last->curve_points = MEM_recallocN(gpc_last->curve_points,
+ sizeof(bGPDcurve_point) * gpc_last->tot_curve_points);
+ /* copy data from first to last */
+ memcpy(gpc_last->curve_points + old_tot_points,
+ gpc_first->curve_points,
+ sizeof(bGPDcurve_point) * first_tot_points);
+
+ BKE_gpencil_editcurve_recalculate_handles(gps_last);
+ gps_last->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps_last);
+
+ /* remove first one */
+ BLI_remlink(&gpf->strokes, gps_first);
+ BKE_gpencil_free_stroke(gps_first);
+ }
+
+ /* Delete the old stroke */
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+}
+
+/* Helper: copy point between strokes */
+static void gpencil_stroke_copy_point(bGPDstroke *gps,
+ MDeformVert *dvert,
+ bGPDspoint *point,
+ const float delta[3],
+ float pressure,
+ float strength,
+ float deltatime)
+{
+ bGPDspoint *newpoint;
+
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
+ }
+ else {
+ /* If destination has weight add weight to origin. */
+ if (dvert != NULL) {
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), __func__);
+ }
+ }
+
+ gps->totpoints++;
+ newpoint = &gps->points[gps->totpoints - 1];
+
+ newpoint->x = point->x * delta[0];
+ newpoint->y = point->y * delta[1];
+ newpoint->z = point->z * delta[2];
+ newpoint->flag = point->flag;
+ newpoint->pressure = pressure;
+ newpoint->strength = strength;
+ newpoint->time = point->time + deltatime;
+ copy_v4_v4(newpoint->vert_color, point->vert_color);
+
+ if (gps->dvert != NULL) {
+ MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1];
+
+ if (dvert != NULL) {
+ newdvert->totweight = dvert->totweight;
+ newdvert->dw = MEM_dupallocN(dvert->dw);
+ }
+ else {
+ newdvert->totweight = 0;
+ newdvert->dw = NULL;
+ }
+ }
+}
+
+/* Join two strokes using the shortest distance (reorder stroke if necessary ) */
+void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
+ bGPDstroke *gps_b,
+ const bool leave_gaps,
+ const bool fit_thickness)
+{
+ bGPDspoint point;
+ bGPDspoint *pt;
+ int i;
+ const float delta[3] = {1.0f, 1.0f, 1.0f};
+ float deltatime = 0.0f;
+
+ /* sanity checks */
+ if (ELEM(NULL, gps_a, gps_b)) {
+ return;
+ }
+
+ if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) {
+ return;
+ }
+
+ /* define start and end points of each stroke */
+ float start_a[3], start_b[3], end_a[3], end_b[3];
+ pt = &gps_a->points[0];
+ copy_v3_v3(start_a, &pt->x);
+
+ pt = &gps_a->points[gps_a->totpoints - 1];
+ copy_v3_v3(end_a, &pt->x);
+
+ pt = &gps_b->points[0];
+ copy_v3_v3(start_b, &pt->x);
+
+ pt = &gps_b->points[gps_b->totpoints - 1];
+ copy_v3_v3(end_b, &pt->x);
+
+ /* Check if need flip strokes. */
+ float dist = len_squared_v3v3(end_a, start_b);
+ bool flip_a = false;
+ bool flip_b = false;
+ float lowest = dist;
+
+ dist = len_squared_v3v3(end_a, end_b);
+ if (dist < lowest) {
+ lowest = dist;
+ flip_a = false;
+ flip_b = true;
+ }
+
+ dist = len_squared_v3v3(start_a, start_b);
+ if (dist < lowest) {
+ lowest = dist;
+ flip_a = true;
+ flip_b = false;
+ }
+
+ dist = len_squared_v3v3(start_a, end_b);
+ if (dist < lowest) {
+ lowest = dist;
+ flip_a = true;
+ flip_b = true;
+ }
+
+ if (flip_a) {
+ BKE_gpencil_stroke_flip(gps_a);
+ }
+ if (flip_b) {
+ BKE_gpencil_stroke_flip(gps_b);
+ }
+
+ /* don't visibly link the first and last points? */
+ if (leave_gaps) {
+ /* 1st: add one tail point to start invisible area */
+ point = gps_a->points[gps_a->totpoints - 1];
+ deltatime = point.time;
+
+ gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f);
+
+ /* 2nd: add one head point to finish invisible area */
+ point = gps_b->points[0];
+ gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime);
+ }
+
+ const float ratio = (fit_thickness && gps_a->thickness > 0.0f) ?
+ (float)gps_b->thickness / (float)gps_a->thickness :
+ 1.0f;
+
+ /* 3rd: add all points */
+ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
+ MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL;
+ gpencil_stroke_copy_point(
+ gps_a, dvert, pt, delta, pt->pressure * ratio, pt->strength, deltatime);
+ }
+}
/** \} */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 79487bf7124..fa3ee0979f1 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1210,9 +1210,11 @@ void nodeUnregisterType(bNodeType *nt)
BLI_ghash_remove(nodetypes_hash, nt->idname, NULL, node_free_type);
}
-bool nodeIsRegistered(bNode *node)
+bool nodeTypeUndefined(bNode *node)
{
- return (node->typeinfo != &NodeTypeUndefined);
+ return (node->typeinfo == &NodeTypeUndefined) ||
+ (node->type == NODE_GROUP && node->id && ID_IS_LINKED(node->id) &&
+ (node->id->tag & LIB_TAG_MISSING));
}
GHashIterator *nodeTypeGetIterator(void)
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index bc1e8b264d9..7e8c412e637 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -4745,7 +4745,7 @@ static bool constructive_modifier_is_deform_modified(ModifierData *md)
if (md->type == eModifierType_MeshSequenceCache) {
/* NOTE: Not ideal because it's unknown whether topology changes or not.
* This will be detected later, so by assuming it's only deformation
- * going on here we allow to bake deform-only mesh to Alembic and have
+ * going on here we allow baking deform-only mesh to Alembic and have
* proper motion blur after that.
*/
return true;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 4117dfc0b23..35ff387c9a6 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -1418,7 +1418,7 @@ static void integrate_particle(
ParticleKey states[5];
float force[3], acceleration[3], impulse[3], dx[4][3] = ZERO_F43, dv[4][3] = ZERO_F43, oldpos[3];
- float pa_mass = (part->flag & PART_SIZEMASS ? part->mass * pa->size : part->mass);
+ float pa_mass = (part->flag & PART_SIZEMASS) ? (part->mass * pa->size) : part->mass;
int i, steps = 1;
int integrator = part->integrator;
@@ -2201,7 +2201,7 @@ static void sph_integrate(ParticleSimulationData *sim,
{
ParticleSettings *part = sim->psys->part;
// float timestep = psys_get_timestep(sim); // UNUSED
- float pa_mass = part->mass * (part->flag & PART_SIZEMASS ? pa->size : 1.0f);
+ float pa_mass = part->mass * ((part->flag & PART_SIZEMASS) ? pa->size : 1.0f);
float dtime = dfra * psys_get_timestep(sim);
// int steps = 1; // UNUSED
float effector_acceleration[3];
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 1393edfe8a2..634db9276a6 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -501,7 +501,7 @@ void BM_mesh_normals_update(BMesh *bm)
{
float(*edgevec)[3] = MEM_mallocN(sizeof(*edgevec) * bm->totedge, __func__);
- /* Parallel mempool iteration does not allow to generate indices inline anymore... */
+ /* Parallel mempool iteration does not allow generating indices inline anymore... */
BM_mesh_elem_index_ensure(bm, (BM_EDGE | BM_FACE));
/* calculate all face normals */
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 46186306fec..7491c309754 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -80,13 +80,13 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
/** Flags for #BM_edge_rotate */
enum {
- /** Disallow to rotate when the new edge matches an existing one. */
+ /** Disallow rotating when the new edge matches an existing one. */
BM_EDGEROT_CHECK_EXISTS = (1 << 0),
/** Overrides existing check, if the edge already, rotate and merge them. */
BM_EDGEROT_CHECK_SPLICE = (1 << 1),
/** Disallow creating bow-tie, concave or zero area faces */
BM_EDGEROT_CHECK_DEGENERATE = (1 << 2),
- /** Disallow to rotate into ugly topology. */
+ /** Disallow rotating into ugly topology. */
BM_EDGEROT_CHECK_BEAUTY = (1 << 3),
};
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp
index f7250de8566..9b3355f535a 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cpp
@@ -136,7 +136,7 @@ Node *Converter::convert(bNode *b_node)
Node *node = nullptr;
/* ignore undefined nodes with missing or invalid node data */
- if (!nodeIsRegistered(b_node)) {
+ if (nodeTypeUndefined(b_node)) {
return nullptr;
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
index 3501a4448c5..312d9f63ce0 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
@@ -161,7 +161,7 @@ void gather_blur(vec2 screen_uv,
for (i = 0, t = ofs * inc; i < KERNEL; i++, t += inc) {
/* Also sample in center motion direction.
- * Allow to recover motion where there is conflicting
+ * Allow recovering motion where there is conflicting
* motion between foreground and background. */
gather_sample(screen_uv,
center_depth,
diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c
index e21b6b30d22..045a38ef374 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_uv.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c
@@ -268,11 +268,13 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata)
if (pd->edit_uv.do_tiled_image_overlay) {
/* Active tile border */
ImageTile *active_tile = BLI_findlink(&image->tiles, image->active_tile_index);
- obmat[3][0] = (float)((active_tile->tile_number - 1001) % 10);
- obmat[3][1] = (float)((active_tile->tile_number - 1001) / 10);
- grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps);
- DRW_shgroup_uniform_vec4_copy(grp, "color", selected_color);
- DRW_shgroup_call_obmat(grp, geom, obmat);
+ if (active_tile) {
+ obmat[3][0] = (float)((active_tile->tile_number - 1001) % 10);
+ obmat[3][1] = (float)((active_tile->tile_number - 1001) / 10);
+ grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", selected_color);
+ DRW_shgroup_call_obmat(grp, geom, obmat);
+ }
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 7217be106ae..8e23199430a 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -51,6 +51,8 @@
#include "BKE_mesh_tangent.h"
#include "BKE_modifier.h"
#include "BKE_object_deform.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
#include "atomic_ops.h"
@@ -1310,6 +1312,17 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
return;
}
+ /* TODO(pablodp606): This always updates the sculpt normals for regular drawing (non-PBVH).
+ * This makes tools that sample the surface per step get wrong normals until a redraw happens.
+ * Normal updates should be part of the brush loop and only run during the stroke when the
+ * brush needs to sample the surface. The drawing code should only update the normals
+ * per redraw when smooth shading is enabled. */
+ const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh;
+ if (do_update_sculpt_normals) {
+ Mesh *mesh = ob->data;
+ BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg);
+ }
+
cache->batch_ready |= batch_requested;
const bool do_cage = (is_editmode &&
diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
index bd6e8436022..78a62c6ae7d 100644
--- a/source/blender/draw/intern/shaders/common_smaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
@@ -240,7 +240,7 @@
* - SMAA::detectMSAAOrder and
* - SMAA::msaaReorder
*
- * These functions allow to match the standard multisample patterns by
+ * These functions allow matching the standard multisample patterns by
* detecting the subsample order for a specific GPU, and reordering
* them appropriately.
*
@@ -1258,8 +1258,8 @@ float4 SMAABlendingWeightCalculationPS(float2 texcoord,
SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].zw, offset[2].y);
d.y = coords.z;
- // We want the distances to be in pixel units (doing this here allow to
- // better interleave arithmetic and memory accesses):
+ // We want the distances to be in pixel units (doing this here allows
+ // better interleaving of arithmetic and memory accesses):
d = abs(round(mad(SMAA_RT_METRICS.zz, d, -pixcoord.xx)));
// SMAAArea below needs a sqrt, as the areas texture is compressed
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 3fb707078b8..09c33c48170 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -430,7 +430,7 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
}
}
}
- /* keyframing modes allow to not replace keyframe */
+ /* Keyframing modes allow not replacing the keyframe. */
else if ((flag & INSERTKEY_REPLACE) == 0) {
/* insert new - if we're not restricted to replacing keyframes only */
BezTriple *newb = MEM_callocN((fcu->totvert + 1) * sizeof(BezTriple), "beztriple");
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index ffa28bf9e36..1e5004ba341 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -159,7 +159,7 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
layout = UI_popup_menu_layout(pup);
- /* special entry - allow to create new group, then use that
+ /* special entry - allow creating a new group, then using that
* (not to be used for removing though)
*/
if (strstr(op->idname, "assign")) {
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index a73bf8154d9..1b53141294e 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -42,6 +42,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -1198,7 +1199,8 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
/* Second Pass: Remove any points that are tagged */
if (do_cull) {
- gpencil_stroke_delete_tagged_points(p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
+ BKE_gpencil_stroke_delete_tagged_points(
+ p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
}
}
}
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 293ce370a0b..33b02d525d5 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1860,7 +1860,8 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op)
if (done) {
/* Delete any selected point. */
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
- gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ BKE_gpencil_stroke_delete_tagged_points(
+ gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
}
BKE_reportf(op->reports, RPT_INFO, "Object created");
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index f2c3804a067..8ce3d176525 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -99,8 +99,6 @@
/** \name Stroke Edit Mode Management
* \{ */
-static void gpencil_flip_stroke(bGPDstroke *gps);
-
/* poll callback for all stroke editing operators */
static bool gpencil_stroke_edit_poll(bContext *C)
{
@@ -1181,7 +1179,7 @@ static void gpencil_add_move_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gp
/* Flip stroke if it was only one point to consider extrude point as last point. */
if (gps->totpoints == 2) {
- gpencil_flip_stroke(gps);
+ BKE_gpencil_stroke_flip(gps);
}
/* Calc geometry data. */
@@ -2584,372 +2582,6 @@ static int gpencil_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
/* ----------------------------------- */
-/* Temp data for storing information about an "island" of points
- * that should be kept when splitting up a stroke. Used in:
- * gpencil_stroke_delete_tagged_points()
- */
-typedef struct tGPDeleteIsland {
- int start_idx;
- int end_idx;
-} tGPDeleteIsland;
-
-static void gpencil_stroke_join_islands(bGPdata *gpd,
- bGPDframe *gpf,
- bGPDstroke *gps_first,
- bGPDstroke *gps_last)
-{
- bGPDspoint *pt = NULL;
- bGPDspoint *pt_final = NULL;
- const int totpoints = gps_first->totpoints + gps_last->totpoints;
-
- /* create new stroke */
- bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false, true);
-
- join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
- join_stroke->totpoints = totpoints;
- join_stroke->flag &= ~GP_STROKE_CYCLIC;
-
- /* copy points (last before) */
- int e1 = 0;
- int e2 = 0;
- float delta = 0.0f;
-
- for (int i = 0; i < totpoints; i++) {
- pt_final = &join_stroke->points[i];
- if (i < gps_last->totpoints) {
- pt = &gps_last->points[e1];
- e1++;
- }
- else {
- pt = &gps_first->points[e2];
- e2++;
- }
-
- /* copy current point */
- copy_v3_v3(&pt_final->x, &pt->x);
- pt_final->pressure = pt->pressure;
- pt_final->strength = pt->strength;
- pt_final->time = delta;
- pt_final->flag = pt->flag;
- copy_v4_v4(pt_final->vert_color, pt->vert_color);
-
- /* retiming with fixed time interval (we cannot determine real time) */
- delta += 0.01f;
- }
-
- /* Copy over vertex weight data (if available) */
- if ((gps_first->dvert != NULL) || (gps_last->dvert != NULL)) {
- join_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * totpoints, __func__);
- MDeformVert *dvert_src = NULL;
- MDeformVert *dvert_dst = NULL;
-
- /* Copy weights (last before)*/
- e1 = 0;
- e2 = 0;
- for (int i = 0; i < totpoints; i++) {
- dvert_dst = &join_stroke->dvert[i];
- dvert_src = NULL;
- if (i < gps_last->totpoints) {
- if (gps_last->dvert) {
- dvert_src = &gps_last->dvert[e1];
- e1++;
- }
- }
- else {
- if (gps_first->dvert) {
- dvert_src = &gps_first->dvert[e2];
- e2++;
- }
- }
-
- if ((dvert_src) && (dvert_src->dw)) {
- dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
- }
- }
- }
-
- /* add new stroke at head */
- BLI_addhead(&gpf->strokes, join_stroke);
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gpd, join_stroke);
-
- /* remove first stroke */
- BLI_remlink(&gpf->strokes, gps_first);
- BKE_gpencil_free_stroke(gps_first);
-
- /* remove last stroke */
- BLI_remlink(&gpf->strokes, gps_last);
- BKE_gpencil_free_stroke(gps_last);
-}
-
-/* Split the given stroke into several new strokes, partitioning
- * it based on whether the stroke points have a particular flag
- * is set (e.g. "GP_SPOINT_SELECT" in most cases, but not always)
- *
- * The algorithm used here is as follows:
- * 1) We firstly identify the number of "islands" of non-tagged points
- * which will all end up being in new strokes.
- * - In the most extreme case (i.e. every other vert is a 1-vert island),
- * we have at most n / 2 islands
- * - Once we start having larger islands than that, the number required
- * becomes much less
- * 2) Each island gets converted to a new stroke
- * If the number of points is <= limit, the stroke is deleted
- */
-void gpencil_stroke_delete_tagged_points(bGPdata *gpd,
- bGPDframe *gpf,
- bGPDstroke *gps,
- bGPDstroke *next_stroke,
- int tag_flags,
- bool select,
- int limit)
-{
- tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2,
- "gp_point_islands");
- bool in_island = false;
- int num_islands = 0;
-
- bGPDstroke *gps_first = NULL;
- const bool is_cyclic = (bool)(gps->flag & GP_STROKE_CYCLIC);
-
- /* First Pass: Identify start/end of islands */
- bGPDspoint *pt = gps->points;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- if (pt->flag & tag_flags) {
- /* selected - stop accumulating to island */
- in_island = false;
- }
- else {
- /* unselected - start of a new island? */
- int idx;
-
- if (in_island) {
- /* extend existing island */
- idx = num_islands - 1;
- islands[idx].end_idx = i;
- }
- else {
- /* start of new island */
- in_island = true;
- num_islands++;
-
- idx = num_islands - 1;
- islands[idx].start_idx = islands[idx].end_idx = i;
- }
- }
- }
-
- /* Watch out for special case where No islands = All points selected = Delete Stroke only */
- if (num_islands) {
- /* There are islands, so create a series of new strokes,
- * adding them before the "next" stroke. */
- int idx;
- bGPDstroke *new_stroke = NULL;
-
- /* Create each new stroke... */
- for (idx = 0; idx < num_islands; idx++) {
- tGPDeleteIsland *island = &islands[idx];
- new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true);
-
- /* if cyclic and first stroke, save to join later */
- if ((is_cyclic) && (gps_first == NULL)) {
- gps_first = new_stroke;
- }
-
- new_stroke->flag &= ~GP_STROKE_CYCLIC;
-
- /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
- new_stroke->totpoints = island->end_idx - island->start_idx + 1;
-
- /* Copy over the relevant point data */
- new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints,
- "gp delete stroke fragment");
- memcpy(new_stroke->points,
- gps->points + island->start_idx,
- sizeof(bGPDspoint) * new_stroke->totpoints);
-
- /* Copy over vertex weight data (if available) */
- if (gps->dvert != NULL) {
- /* Copy over the relevant vertex-weight points */
- new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints,
- "gp delete stroke fragment weight");
- memcpy(new_stroke->dvert,
- gps->dvert + island->start_idx,
- sizeof(MDeformVert) * new_stroke->totpoints);
-
- /* Copy weights */
- int e = island->start_idx;
- for (int i = 0; i < new_stroke->totpoints; i++) {
- MDeformVert *dvert_src = &gps->dvert[e];
- MDeformVert *dvert_dst = &new_stroke->dvert[i];
- if (dvert_src->dw) {
- dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
- }
- e++;
- }
- }
- /* Each island corresponds to a new stroke.
- * We must adjust the timings of these new strokes:
- *
- * Each point's timing data is a delta from stroke's inittime, so as we erase some points
- * from the start of the stroke, we have to offset this inittime and all remaining points'
- * delta values. This way we get a new stroke with exactly the same timing as if user had
- * started drawing from the first non-removed point.
- */
- {
- bGPDspoint *pts;
- float delta = gps->points[island->start_idx].time;
- int j;
-
- new_stroke->inittime += (double)delta;
-
- pts = new_stroke->points;
- for (j = 0; j < new_stroke->totpoints; j++, pts++) {
- pts->time -= delta;
- /* set flag for select again later */
- if (select == true) {
- pts->flag &= ~GP_SPOINT_SELECT;
- pts->flag |= GP_SPOINT_TAG;
- }
- }
- }
-
- /* Add new stroke to the frame or delete if below limit */
- if ((limit > 0) && (new_stroke->totpoints <= limit)) {
- BKE_gpencil_free_stroke(new_stroke);
- }
- else {
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
-
- if (next_stroke) {
- BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
- }
- else {
- BLI_addtail(&gpf->strokes, new_stroke);
- }
- }
- }
- /* if cyclic, need to join last stroke with first stroke */
- if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) {
- gpencil_stroke_join_islands(gpd, gpf, gps_first, new_stroke);
- }
- }
-
- /* free islands */
- MEM_freeN(islands);
-
- /* Delete the old stroke */
- BLI_remlink(&gpf->strokes, gps);
- BKE_gpencil_free_stroke(gps);
-}
-
-static void gpencil_curve_delete_tagged_points(bGPdata *gpd,
- bGPDframe *gpf,
- bGPDstroke *gps,
- bGPDstroke *next_stroke,
- bGPDcurve *gpc,
- int tag_flags)
-{
- if (gpc == NULL) {
- return;
- }
- const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
- const int idx_last = gpc->tot_curve_points - 1;
- bGPDstroke *gps_first = NULL;
- bGPDstroke *gps_last = NULL;
-
- int idx_start = 0;
- int idx_end = 0;
- bool prev_selected = gpc->curve_points[0].flag & tag_flags;
- for (int i = 1; i < gpc->tot_curve_points; i++) {
- bool selected = gpc->curve_points[i].flag & tag_flags;
- if (prev_selected == true && selected == false) {
- idx_start = i;
- }
- /* Island ends if the current point is selected or if we reached the end of the stroke */
- if ((prev_selected == false && selected == true) || (selected == false && i == idx_last)) {
-
- idx_end = selected ? i - 1 : i;
- int island_length = idx_end - idx_start + 1;
-
- /* If an island has only a single curve point, there is no curve segment, so skip island */
- if (island_length == 1) {
- if (is_cyclic) {
- if (idx_start > 0 && idx_end < idx_last) {
- prev_selected = selected;
- continue;
- }
- }
- else {
- prev_selected = selected;
- continue;
- }
- }
-
- bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, false, false);
- new_stroke->points = NULL;
- new_stroke->flag &= ~GP_STROKE_CYCLIC;
- new_stroke->editcurve = BKE_gpencil_stroke_editcurve_new(island_length);
-
- if (gps_first == NULL) {
- gps_first = new_stroke;
- }
-
- bGPDcurve *new_gpc = new_stroke->editcurve;
- memcpy(new_gpc->curve_points,
- gpc->curve_points + idx_start,
- sizeof(bGPDcurve_point) * island_length);
-
- BKE_gpencil_editcurve_recalculate_handles(new_stroke);
- new_stroke->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
-
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
-
- if (next_stroke) {
- BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
- }
- else {
- BLI_addtail(&gpf->strokes, new_stroke);
- }
-
- gps_last = new_stroke;
- }
- prev_selected = selected;
- }
-
- /* join first and last stroke if cyclic */
- if (is_cyclic && gps_first != NULL && gps_last != NULL && gps_first != gps_last) {
- bGPDcurve *gpc_first = gps_first->editcurve;
- bGPDcurve *gpc_last = gps_last->editcurve;
- int first_tot_points = gpc_first->tot_curve_points;
- int old_tot_points = gpc_last->tot_curve_points;
-
- gpc_last->tot_curve_points = first_tot_points + old_tot_points;
- gpc_last->curve_points = MEM_recallocN(gpc_last->curve_points,
- sizeof(bGPDcurve_point) * gpc_last->tot_curve_points);
- /* copy data from first to last */
- memcpy(gpc_last->curve_points + old_tot_points,
- gpc_first->curve_points,
- sizeof(bGPDcurve_point) * first_tot_points);
-
- BKE_gpencil_editcurve_recalculate_handles(gps_last);
- gps_last->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
-
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gpd, gps_last);
-
- /* remove first one */
- BLI_remlink(&gpf->strokes, gps_first);
- BKE_gpencil_free_stroke(gps_first);
- }
-
- /* Delete the old stroke */
- BLI_remlink(&gpf->strokes, gps);
- BKE_gpencil_free_stroke(gps);
-}
-
/* Split selected strokes into segments, splitting on selected points */
static int gpencil_delete_selected_points(bContext *C)
{
@@ -2987,12 +2619,12 @@ static int gpencil_delete_selected_points(bContext *C)
if (is_curve_edit) {
bGPDcurve *gpc = gps->editcurve;
- gpencil_curve_delete_tagged_points(
+ BKE_gpencil_curve_delete_tagged_points(
gpd, gpf, gps, gps->next, gpc, GP_CURVE_POINT_SELECT);
}
else {
/* delete unwanted points by splitting stroke into several smaller ones */
- gpencil_stroke_delete_tagged_points(
+ BKE_gpencil_stroke_delete_tagged_points(
gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
}
@@ -3828,188 +3460,6 @@ void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
/** \name Stroke Join Operator
* \{ */
-/* Helper: flip stroke */
-static void gpencil_flip_stroke(bGPDstroke *gps)
-{
- int end = gps->totpoints - 1;
-
- for (int i = 0; i < gps->totpoints / 2; i++) {
- bGPDspoint *point, *point2;
- bGPDspoint pt;
-
- /* save first point */
- point = &gps->points[i];
- pt.x = point->x;
- pt.y = point->y;
- pt.z = point->z;
- pt.flag = point->flag;
- pt.pressure = point->pressure;
- pt.strength = point->strength;
- pt.time = point->time;
- copy_v4_v4(pt.vert_color, point->vert_color);
-
- /* replace first point with last point */
- point2 = &gps->points[end];
- point->x = point2->x;
- point->y = point2->y;
- point->z = point2->z;
- point->flag = point2->flag;
- point->pressure = point2->pressure;
- point->strength = point2->strength;
- point->time = point2->time;
- copy_v4_v4(point->vert_color, point2->vert_color);
-
- /* replace last point with first saved before */
- point = &gps->points[end];
- point->x = pt.x;
- point->y = pt.y;
- point->z = pt.z;
- point->flag = pt.flag;
- point->pressure = pt.pressure;
- point->strength = pt.strength;
- point->time = pt.time;
- copy_v4_v4(point->vert_color, pt.vert_color);
-
- end--;
- }
-}
-
-/* Helper: copy point between strokes */
-static void gpencil_stroke_copy_point(bGPDstroke *gps,
- MDeformVert *dvert,
- bGPDspoint *point,
- const float delta[3],
- float pressure,
- float strength,
- float deltatime)
-{
- bGPDspoint *newpoint;
-
- gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
- if (gps->dvert != NULL) {
- gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
- }
- else {
- /* If destination has weight add weight to origin. */
- if (dvert != NULL) {
- gps->dvert = MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), __func__);
- }
- }
-
- gps->totpoints++;
- newpoint = &gps->points[gps->totpoints - 1];
-
- newpoint->x = point->x * delta[0];
- newpoint->y = point->y * delta[1];
- newpoint->z = point->z * delta[2];
- newpoint->flag = point->flag;
- newpoint->pressure = pressure;
- newpoint->strength = strength;
- newpoint->time = point->time + deltatime;
- copy_v4_v4(newpoint->vert_color, point->vert_color);
-
- if (gps->dvert != NULL) {
- MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1];
-
- if (dvert != NULL) {
- newdvert->totweight = dvert->totweight;
- newdvert->dw = MEM_dupallocN(dvert->dw);
- }
- else {
- newdvert->totweight = 0;
- newdvert->dw = NULL;
- }
- }
-}
-
-/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
-static void gpencil_stroke_join_strokes(bGPDstroke *gps_a,
- bGPDstroke *gps_b,
- const bool leave_gaps)
-{
- bGPDspoint point;
- bGPDspoint *pt;
- int i;
- const float delta[3] = {1.0f, 1.0f, 1.0f};
- float deltatime = 0.0f;
-
- /* sanity checks */
- if (ELEM(NULL, gps_a, gps_b)) {
- return;
- }
-
- if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) {
- return;
- }
-
- /* define start and end points of each stroke */
- float start_a[3], start_b[3], end_a[3], end_b[3];
- pt = &gps_a->points[0];
- copy_v3_v3(start_a, &pt->x);
-
- pt = &gps_a->points[gps_a->totpoints - 1];
- copy_v3_v3(end_a, &pt->x);
-
- pt = &gps_b->points[0];
- copy_v3_v3(start_b, &pt->x);
-
- pt = &gps_b->points[gps_b->totpoints - 1];
- copy_v3_v3(end_b, &pt->x);
-
- /* Check if need flip strokes. */
- float dist = len_squared_v3v3(end_a, start_b);
- bool flip_a = false;
- bool flip_b = false;
- float lowest = dist;
-
- dist = len_squared_v3v3(end_a, end_b);
- if (dist < lowest) {
- lowest = dist;
- flip_a = false;
- flip_b = true;
- }
-
- dist = len_squared_v3v3(start_a, start_b);
- if (dist < lowest) {
- lowest = dist;
- flip_a = true;
- flip_b = false;
- }
-
- dist = len_squared_v3v3(start_a, end_b);
- if (dist < lowest) {
- lowest = dist;
- flip_a = true;
- flip_b = true;
- }
-
- if (flip_a) {
- gpencil_flip_stroke(gps_a);
- }
- if (flip_b) {
- gpencil_flip_stroke(gps_b);
- }
-
- /* don't visibly link the first and last points? */
- if (leave_gaps) {
- /* 1st: add one tail point to start invisible area */
- point = gps_a->points[gps_a->totpoints - 1];
- deltatime = point.time;
-
- gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f);
-
- /* 2nd: add one head point to finish invisible area */
- point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime);
- }
-
- /* 3rd: add all points */
- for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
- MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL;
- gpencil_stroke_copy_point(gps_a, dvert, pt, delta, pt->pressure, pt->strength, deltatime);
- }
-}
-
typedef struct tJoinStrokes {
bGPDframe *gpf;
bGPDstroke *gps;
@@ -4159,7 +3609,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
}
elem = &strokes_list[i];
/* Join new_stroke and stroke B. */
- gpencil_stroke_join_strokes(gps_new, elem->gps, leave_gaps);
+ BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true);
elem->used = true;
}
@@ -4254,8 +3704,8 @@ static int gpencil_stroke_flip_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Not implemented!");
}
else {
- /* flip stroke */
- gpencil_flip_stroke(gps);
+ /* Flip stroke. */
+ BKE_gpencil_stroke_flip(gps);
}
changed = true;
@@ -5108,11 +4558,11 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
}
/* delete selected points from destination stroke */
- gpencil_stroke_delete_tagged_points(
+ BKE_gpencil_stroke_delete_tagged_points(
gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0);
/* delete selected points from origin stroke */
- gpencil_stroke_delete_tagged_points(
+ BKE_gpencil_stroke_delete_tagged_points(
gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
}
}
@@ -5287,11 +4737,11 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *op)
}
/* delete selected points from destination stroke */
- gpencil_stroke_delete_tagged_points(
+ BKE_gpencil_stroke_delete_tagged_points(
gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0);
/* delete selected points from origin stroke */
- gpencil_stroke_delete_tagged_points(
+ BKE_gpencil_stroke_delete_tagged_points(
gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
}
}
@@ -5487,7 +4937,7 @@ static void gpencil_cutter_dissolve(bGPdata *gpd,
}
}
- gpencil_stroke_delete_tagged_points(
+ BKE_gpencil_stroke_delete_tagged_points(
gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index e4e9a3ae0ab..0bdd2033491 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -152,6 +152,31 @@ typedef struct tGPDinterpolate {
NumInput num; /* numeric input */
} tGPDinterpolate;
+/* Modal Operator Drawing Callbacks ------------------------ */
+void ED_gpencil_draw_fill(struct tGPDdraw *tgpw);
+
+/* ***************************************************** */
+/* Internal API */
+
+/* Stroke Coordinates API ------------------------------ */
+/* gpencil_utils.c */
+
+typedef struct GP_SpaceConversion {
+ struct Scene *scene;
+ struct Object *ob;
+ struct bGPdata *gpd;
+ struct bGPDlayer *gpl;
+
+ struct ScrArea *area;
+ struct ARegion *region;
+ struct View2D *v2d;
+
+ rctf *subrect; /* for using the camera rect within the 3d view */
+ rctf subrect_data;
+
+ float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
+} GP_SpaceConversion;
+
/* Temporary primitive operation data */
typedef struct tGPDprimitive {
/** main database pointer */
@@ -180,6 +205,9 @@ typedef struct tGPDprimitive {
/** current brush */
struct Brush *brush;
+ /** Settings to pass to gp_points_to_xy(). */
+ GP_SpaceConversion gsc;
+
/** current frame number */
int cframe;
/** layer */
@@ -248,31 +276,6 @@ typedef struct tGPDprimitive {
} tGPDprimitive;
-/* Modal Operator Drawing Callbacks ------------------------ */
-void ED_gpencil_draw_fill(struct tGPDdraw *tgpw);
-
-/* ***************************************************** */
-/* Internal API */
-
-/* Stroke Coordinates API ------------------------------ */
-/* gpencil_utils.c */
-
-typedef struct GP_SpaceConversion {
- struct Scene *scene;
- struct Object *ob;
- struct bGPdata *gpd;
- struct bGPDlayer *gpl;
-
- struct ScrArea *area;
- struct ARegion *region;
- struct View2D *v2d;
-
- rctf *subrect; /* for using the camera rect within the 3d view */
- rctf subrect_data;
-
- float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
-} GP_SpaceConversion;
-
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1);
void gpencil_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
@@ -343,13 +346,6 @@ struct GHash *gpencil_copybuf_validate_colormap(struct bContext *C);
/* Stroke Editing ------------------------------------ */
-void gpencil_stroke_delete_tagged_points(bGPdata *gpd,
- bGPDframe *gpf,
- bGPDstroke *gps,
- bGPDstroke *next_stroke,
- int tag_flags,
- bool select,
- int limit);
int gpencil_delete_selected_point_wrap(bContext *C);
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide);
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index f795ed01bb8..9f2bf3818a4 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -182,7 +182,7 @@ static void gpencil_dissolve_points(bContext *C)
}
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
- gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
+ BKE_gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
}
}
CTX_DATA_END;
diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c
index 2dd98bb8df1..4721736489e 100644
--- a/source/blender/editors/gpencil/gpencil_ops_versioning.c
+++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c
@@ -22,7 +22,7 @@
* \ingroup edgpencil
*/
-/* allow to use deprecated functionality */
+/* Allow using deprecated functionality. */
#define DNA_DEPRECATED_ALLOW
#include <stdio.h>
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index e544093cd1d..14313a50118 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1282,6 +1282,25 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
BKE_gpencil_stroke_trim(gpd, gps);
}
+ /* Join with existing strokes. */
+ if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
+ if (gps->prev != NULL) {
+ int pt_index = 0;
+ bool doit = true;
+ while (doit && gps) {
+ bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(
+ p->C, &p->gsc, gpl, gpl->actframe, gps, GPENCIL_MINIMUM_JOIN_DIST, &pt_index);
+ if (gps_target != NULL) {
+ gps = ED_gpencil_stroke_join_and_trim(p->gpd, p->gpf, gps, gps_target, pt_index);
+ }
+ else {
+ doit = false;
+ }
+ }
+ }
+ ED_gpencil_stroke_close_by_distance(gps, 0.02f);
+ }
+
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gpd, gps);
@@ -1652,7 +1671,8 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
gpencil_stroke_soft_refine(gps);
}
- gpencil_stroke_delete_tagged_points(p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
+ BKE_gpencil_stroke_delete_tagged_points(
+ p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
}
gpencil_update_cache(p->gpd);
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 801dacb3e6b..b457cd819d2 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -1197,6 +1197,9 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* set GP datablock */
tgpi->gpd = gpd;
+ /* Setup space conversions. */
+ gpencil_point_conversion_init(C, &tgpi->gsc);
+
/* if brush doesn't exist, create a new set (fix damaged files from old versions) */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
BKE_brush_gpencil_paint_presets(bmain, ts, true);
@@ -1347,6 +1350,28 @@ static void gpencil_primitive_interaction_end(bContext *C,
}
}
+ /* Join previous stroke. */
+ if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
+ if (ELEM(tgpi->type, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_CURVE, GP_STROKE_POLYLINE)) {
+ if (gps->prev != NULL) {
+ int pt_index = 0;
+ bool doit = true;
+ while (doit && gps) {
+ bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(
+ C, &tgpi->gsc, tgpi->gpl, gpf, gps, GPENCIL_MINIMUM_JOIN_DIST, &pt_index);
+ if (gps_target != NULL) {
+ gps = ED_gpencil_stroke_join_and_trim(tgpi->gpd, gpf, gps, gps_target, pt_index);
+ }
+ else {
+ doit = false;
+ }
+ }
+ }
+ ED_gpencil_stroke_close_by_distance(gps, 0.02f);
+ }
+ BKE_gpencil_stroke_geometry_update(tgpi->gpd, gps);
+ }
+
DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE);
DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 76a584fcac1..af63c5ca3b2 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -148,7 +148,6 @@ bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
case SPACE_INFO: /* header info */
{
return NULL;
- break;
}
case SPACE_TOPBAR: /* Top-bar */
@@ -3106,3 +3105,181 @@ bool ED_gpencil_stroke_point_is_inside(bGPDstroke *gps,
return hit;
}
+
+bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
+ GP_SpaceConversion *gsc,
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ const float radius,
+ int *r_index)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPDstroke *gps_rtn = NULL;
+ const float radius_sqr = radius * radius;
+
+ /* calculate difference matrix object */
+ float diff_mat[4][4];
+ BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
+
+ /* Calculate the extremes of the stroke in 2D. */
+ bGPDspoint pt_parent;
+ float pt2d_start[2], pt2d_end[2];
+
+ bGPDspoint *pt = &gps->points[0];
+ gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_start[0], &pt2d_start[1]);
+
+ pt = &gps->points[gps->totpoints - 1];
+ gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_end[0], &pt2d_end[1]);
+
+ /* Loop all strokes of the active frame. */
+ float dist_min = FLT_MAX;
+ LISTBASE_FOREACH (bGPDstroke *, gps_target, &gpf->strokes) {
+ /* Check if the color is editable. */
+ if ((gps_target == gps) || (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)) {
+ continue;
+ }
+
+ /* Check if one of the ends is inside target stroke bounding box. */
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, pt2d_start, radius, diff_mat)) {
+ continue;
+ }
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, pt2d_end, radius, diff_mat)) {
+ continue;
+ }
+ /* Check the distance of the ends with the ends of target stroke to avoid middle contact.
+ * All is done in 2D plane. */
+ float pt2d_target_start[2], pt2d_target_end[2];
+
+ pt = &gps_target->points[0];
+ gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_start[0], &pt2d_target_start[1]);
+
+ pt = &gps_target->points[gps_target->totpoints - 1];
+ gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_end[0], &pt2d_target_end[1]);
+
+ if ((len_squared_v2v2(pt2d_start, pt2d_target_start) > radius_sqr) &&
+ (len_squared_v2v2(pt2d_start, pt2d_target_end) > radius_sqr) &&
+ (len_squared_v2v2(pt2d_end, pt2d_target_start) > radius_sqr) &&
+ (len_squared_v2v2(pt2d_end, pt2d_target_end) > radius_sqr)) {
+ continue;
+ }
+
+ /* Loop all points and check what is the nearest point. */
+ int i;
+ for (i = 0, pt = gps_target->points; i < gps_target->totpoints; i++, pt++) {
+ /* Convert point to 2D. */
+ float pt2d[2];
+ gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d[0], &pt2d[1]);
+
+ /* Check with Start point. */
+ float dist = len_squared_v2v2(pt2d, pt2d_start);
+ if ((dist <= radius_sqr) && (dist < dist_min)) {
+ *r_index = i;
+ dist_min = dist;
+ gps_rtn = gps_target;
+ }
+ /* Check with End point. */
+ dist = len_squared_v2v2(pt2d, pt2d_end);
+ if ((dist <= radius_sqr) && (dist < dist_min)) {
+ *r_index = i;
+ dist_min = dist;
+ gps_rtn = gps_target;
+ }
+ }
+ }
+
+ return gps_rtn;
+}
+
+/* Join two stroke using a contact point index and trimming the rest. */
+bGPDstroke *ED_gpencil_stroke_join_and_trim(
+ bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *gps_dst, const int pt_index)
+{
+ if ((gps->totpoints < 1) || (gps_dst->totpoints < 1)) {
+ return false;
+ }
+ BLI_assert(pt_index >= 0 && pt_index < gps_dst->totpoints);
+
+ bGPDspoint *pt = NULL;
+
+ /* Cannot be cyclic. */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ gps_dst->flag &= ~GP_STROKE_CYCLIC;
+
+ /* Trim stroke. */
+ bGPDstroke *gps_final = gps_dst;
+ if ((pt_index > 0) && (pt_index < gps_dst->totpoints - 2)) {
+ /* Untag any pending operation. */
+ gps_dst->flag &= ~GP_STROKE_TAG;
+ for (int i = 0; i < gps_dst->totpoints; i++) {
+ gps_dst->points[i].flag &= ~GP_SPOINT_TAG;
+ }
+
+ /* Delete points of the shorter extreme */
+ pt = &gps_dst->points[0];
+ float dist_to_start = BKE_gpencil_stroke_segment_length(gps_dst, 0, pt_index, true);
+ pt = &gps_dst->points[gps_dst->totpoints - 1];
+ float dist_to_end = BKE_gpencil_stroke_segment_length(
+ gps_dst, pt_index, gps_dst->totpoints - 1, true);
+
+ if (dist_to_start < dist_to_end) {
+ for (int i = 0; i < pt_index; i++) {
+ gps_dst->points[i].flag |= GP_SPOINT_TAG;
+ }
+ }
+ else {
+ for (int i = pt_index + 1; i < gps_dst->totpoints; i++) {
+ gps_dst->points[i].flag |= GP_SPOINT_TAG;
+ }
+ }
+ /* Remove tagged points to trim stroke. */
+ gps_final = BKE_gpencil_stroke_delete_tagged_points(
+ gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, 0);
+ }
+
+ /* Join both strokes. */
+ int totpoint = gps_final->totpoints;
+ BKE_gpencil_stroke_join(gps_final, gps, false, true);
+
+ /* Select the join points and merge if the distance is very small. */
+ pt = &gps_final->points[totpoint - 1];
+ pt->flag |= GP_SPOINT_SELECT;
+
+ pt = &gps_final->points[totpoint];
+ pt->flag |= GP_SPOINT_SELECT;
+ BKE_gpencil_stroke_merge_distance(gpd, gpf, gps_final, 0.01f, false);
+
+ /* Unselect all points. */
+ for (int i = 0; i < gps_final->totpoints; i++) {
+ gps_final->points[i].flag &= ~GP_SPOINT_SELECT;
+ }
+
+ /* Delete old stroke. */
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+
+ return gps_final;
+}
+
+/* Close if the distance between extremes is below threshold. */
+void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
+{
+ if (gps == NULL) {
+ return;
+ }
+ bGPDspoint *pt_start = &gps->points[0];
+ bGPDspoint *pt_end = &gps->points[gps->totpoints - 1];
+
+ const float threshold_sqr = threshold * threshold;
+ float dist_to_close = len_squared_v3v3(&pt_start->x, &pt_end->x);
+ if (dist_to_close < threshold_sqr) {
+ gps->flag |= GP_STROKE_CYCLIC;
+ BKE_gpencil_stroke_close(gps);
+ }
+}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 17aa407bd76..be2f714dfe1 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -63,6 +63,8 @@ struct bAnimContext;
struct wmKeyConfig;
struct wmOperator;
+#define GPENCIL_MINIMUM_JOIN_DIST 20.0f
+
/* Reproject stroke modes. */
typedef enum eGP_ReprojectModes {
/* Axis */
@@ -366,6 +368,22 @@ bool ED_gpencil_stroke_point_is_inside(struct bGPDstroke *gps,
int mouse[2],
const float diff_mat[4][4]);
+struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C,
+ struct GP_SpaceConversion *gsc,
+ struct bGPDlayer *gpl,
+ struct bGPDframe *gpf,
+ struct bGPDstroke *gps,
+ const float radius,
+ int *r_index);
+
+struct bGPDstroke *ED_gpencil_stroke_join_and_trim(struct bGPdata *gpd,
+ struct bGPDframe *gpf,
+ struct bGPDstroke *gps,
+ struct bGPDstroke *gps_dst,
+ const int pt_index);
+
+void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, const float threshold);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index a55e97fff72..2066d7da511 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -241,6 +241,7 @@ struct UVPackIsland_Params {
int rotate_align_axis : 2;
uint only_selected_uvs : 1;
uint only_selected_faces : 1;
+ uint use_seams : 1;
uint correct_aspect : 1;
};
void ED_uvedit_pack_islands_multi(const Scene *scene,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index d99ecf2fd56..b7eb5cab7f9 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -263,7 +263,7 @@ DEF_ICON(LIBRARY_DATA_BROKEN)
DEF_ICON(BOIDS)
DEF_ICON(STRANDS)
DEF_ICON(LIBRARY_DATA_INDIRECT)
-DEF_ICON_OBJECT_DATA(GREASEPENCIL)
+DEF_ICON(GREASEPENCIL)
DEF_ICON_SHADING(LINE_DATA)
DEF_ICON(LIBRARY_DATA_OVERRIDE)
DEF_ICON(GROUP_BONE)
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 02e083076f0..1b87f5081b6 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -64,6 +64,7 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
+#include "UI_view2d.h"
#include "IMB_imbuf.h"
@@ -286,11 +287,12 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
}
}
+ const float view_scale_x = UI_view2d_scale_get_x(&region->v2d);
const float segment_width = region_width / (float)sepr_flex_len;
float offset = 0, remaining_space = region_width - buttons_width;
i = 0;
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- BLI_rctf_translate(&but->rect, offset, 0);
+ BLI_rctf_translate(&but->rect, offset / view_scale_x, 0);
if (but->type == UI_BTYPE_SEPR_SPACER) {
/* How much the next block overlap with the current segment */
int overlap = ((i == sepr_flex_len - 1) ? buttons_width - spacers_pos[i] :
diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
index f7c41a7142b..7f735a0e789 100644
--- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
@@ -299,7 +299,6 @@ static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent *
eyedropper_gpencil_exit(C, op);
return OPERATOR_FINISHED;
- break;
}
default: {
break;
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index af71306cc3b..7dd6e400ae7 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -365,7 +365,7 @@ typedef struct uiHandleButtonData {
/* Button text selection:
* extension direction, selextend, inside ui_do_but_TEX */
int sel_pos_init;
- /* allow to realloc str/editstr and use 'maxlen' to track alloc size (maxlen + 1) */
+ /* Allow reallocating str/editstr and using 'maxlen' to track alloc size (maxlen + 1) */
bool is_str_dynamic;
/* number editing / dragging */
@@ -818,21 +818,25 @@ static void ui_apply_but_undo(uiBut *but)
{
if (but->flag & UI_BUT_UNDO) {
const char *str = NULL;
+ size_t str_len_clip = SIZE_MAX - 1;
bool skip_undo = false;
/* define which string to use for undo */
if (but->type == UI_BTYPE_MENU) {
str = but->drawstr;
+ str_len_clip = ui_but_drawstr_len_without_sep_char(but);
}
else if (but->drawstr[0]) {
str = but->drawstr;
+ str_len_clip = ui_but_drawstr_len_without_sep_char(but);
}
else {
str = but->tip;
+ str_len_clip = ui_but_tip_len_only_first_line(but);
}
/* fallback, else we don't get an undo! */
- if (str == NULL || str[0] == '\0') {
+ if (str == NULL || str[0] == '\0' || str_len_clip == 0) {
str = "Unknown Action";
}
@@ -869,7 +873,7 @@ static void ui_apply_but_undo(uiBut *but)
/* delayed, after all other funcs run, popups are closed, etc */
uiAfterFunc *after = ui_afterfunc_new();
- BLI_strncpy(after->undostr, str, sizeof(after->undostr));
+ BLI_strncpy(after->undostr, str, min_zz(str_len_clip + 1, sizeof(after->undostr)));
}
}
@@ -10228,8 +10232,7 @@ static int ui_but_pie_menu_apply(bContext *C,
menu->menuretval = UI_RETURN_CANCEL;
}
else {
- ui_apply_but(C, but->block, but, but->active, false);
- button_activate_exit((bContext *)C, but, but->active, false, true);
+ button_activate_exit((bContext *)C, but, but->active, false, false);
menu->menuretval = UI_RETURN_OK;
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 68d837ba4b4..90f5172f6ec 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -2263,7 +2263,7 @@ int UI_icon_from_idcode(const int idcode)
case ID_CU:
return ICON_CURVE_DATA;
case ID_GD:
- return ICON_GREASEPENCIL;
+ return ICON_OUTLINER_DATA_GREASEPENCIL;
case ID_GR:
return ICON_OUTLINER_COLLECTION;
case ID_IM:
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index c4b54af1396..13234c82bfa 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -1089,6 +1089,9 @@ uiBut *ui_list_find_mouse_over_ex(struct ARegion *region, int x, int y) ATTR_WAR
bool ui_but_contains_password(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+size_t ui_but_drawstr_len_without_sep_char(const uiBut *but);
+size_t ui_but_tip_len_only_first_line(const uiBut *but);
+
uiBut *ui_but_prev(uiBut *but) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_but_next(uiBut *but) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_but_first(uiBlock *block) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index bd42e5db531..d61e80e6505 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -956,7 +956,7 @@ static uiBut *ui_item_with_label(uiLayout *layout,
#endif
const bool is_keymapitem_ptr = RNA_struct_is_a(ptr->type, &RNA_KeyMapItem);
- if ((flag & flag & UI_ITEM_R_FULL_EVENT) && !is_keymapitem_ptr) {
+ if ((flag & UI_ITEM_R_FULL_EVENT) && !is_keymapitem_ptr) {
RNA_warning("Data is not a keymap item struct: %s. Ignoring 'full_event' option.",
RNA_struct_identifier(ptr->type));
}
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 6b6d9a76313..839363c9599 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -138,29 +138,6 @@ static bool panel_type_context_poll(ARegion *region,
/** \name Local Functions
* \{ */
-static void panel_title_color_get(const Panel *panel,
- const bool show_background,
- const bool region_search_filter_active,
- uchar r_color[4])
-{
- if (!show_background) {
- /* Use menu colors for floating panels. */
- bTheme *btheme = UI_GetTheme();
- const uiWidgetColors *wcol = &btheme->tui.wcol_menu_back;
- copy_v4_v4_uchar(r_color, (const uchar *)wcol->text);
- return;
- }
-
- const bool search_match = UI_panel_matches_search_filter(panel);
-
- UI_GetThemeColor4ubv(TH_TITLE, r_color);
- if (region_search_filter_active && !search_match) {
- r_color[0] *= 0.5;
- r_color[1] *= 0.5;
- r_color[2] *= 0.5;
- }
-}
-
static bool panel_active_animation_changed(ListBase *lb,
Panel **r_panel_animation,
bool *r_no_animation)
@@ -1062,265 +1039,253 @@ void UI_panel_label_offset(const uiBlock *block, int *r_x, int *r_y)
}
}
-static void ui_draw_aligned_panel_header(const uiStyle *style,
- const uiBlock *block,
- const rcti *rect,
- const bool show_background,
- const bool region_search_filter_active)
-{
- const Panel *panel = block->panel;
- const bool is_subpanel = (panel->type && panel->type->parent);
- const uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
-
- /* + 0.001f to avoid flirting with float inaccuracy .*/
- const int pnl_icons = (panel->labelofs + (1.1f * PNL_ICON)) / block->aspect + 0.001f;
-
- /* Draw text labels. */
- uchar col_title[4];
- panel_title_color_get(panel, show_background, region_search_filter_active, col_title);
- col_title[3] = 255;
-
- rcti hrect = *rect;
- hrect.xmin = rect->xmin + pnl_icons;
- hrect.ymin -= 2.0f / block->aspect;
- UI_fontstyle_draw(fontstyle,
- &hrect,
- panel->drawname,
- col_title,
- &(struct uiFontStyleDraw_Params){
- .align = UI_STYLE_TEXT_LEFT,
- });
-}
-
-/**
- * Draw a panel integrated in buttons-window, tool/property lists etc.
- */
-void ui_draw_aligned_panel(const uiStyle *style,
- const uiBlock *block,
- const rcti *rect,
- const bool show_pin,
- const bool show_background,
- const bool region_search_filter_active)
+static void panel_title_color_get(const Panel *panel,
+ const bool show_background,
+ const bool region_search_filter_active,
+ uchar r_color[4])
{
- const Panel *panel = block->panel;
- float color[4];
- const bool is_subpanel = (panel->type && panel->type->parent);
- const bool show_drag = (!is_subpanel &&
- /* FIXME(campbell): currently no background means floating panel which
- * can't be dragged. This may be changed in future. */
- show_background);
- const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK;
- const bool draw_box_style = (panel->type && panel->type->flag & PANEL_TYPE_DRAW_BOX);
-
- /* Use the theme for box widgets for box-style panels. */
- uiWidgetColors *box_wcol = NULL;
- if (draw_box_style) {
+ if (!show_background) {
+ /* Use menu colors for floating panels. */
bTheme *btheme = UI_GetTheme();
- box_wcol = &btheme->tui.wcol_box;
- }
-
- const uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- if (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER)) {
- if (show_background) {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformThemeColor(panel_col);
- immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- immUnbindProgram();
- }
+ const uiWidgetColors *wcol = &btheme->tui.wcol_menu_back;
+ copy_v4_v4_uchar(r_color, (const uchar *)wcol->text);
return;
}
- /* Calculate header rectangle with + 0.001f to prevent flicker due to float inaccuracy. */
- rcti headrect = {
- rect->xmin, rect->xmax, rect->ymax, rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f)};
-
- /* Draw a panel and header backdrops with an opaque box backdrop for box style panels. */
- if (draw_box_style && !is_subpanel) {
- /* Expand the top a tiny bit to give header buttons equal size above and below. */
- rcti box_rect = {rect->xmin,
- rect->xmax,
- UI_panel_is_closed(panel) ? headrect.ymin : rect->ymin,
- headrect.ymax + U.pixelsize};
- ui_draw_box_opaque(&box_rect, UI_CNR_ALL);
+ const bool search_match = UI_panel_matches_search_filter(panel);
- /* Mimic the border between aligned box widgets for the bottom of the header. */
- if (!UI_panel_is_closed(panel)) {
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_blend(GPU_BLEND_ALPHA);
-
- immUniformColor4ubv(box_wcol->outline);
- immRectf(pos, rect->xmin, headrect.ymin - U.pixelsize, rect->xmax, headrect.ymin);
- uchar emboss_col[4];
- UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col);
- immUniformColor4ubv(emboss_col);
- immRectf(pos,
- rect->xmin,
- headrect.ymin - U.pixelsize,
- rect->xmax,
- headrect.ymin - U.pixelsize - 1);
-
- GPU_blend(GPU_BLEND_NONE);
- immUnbindProgram();
- }
+ UI_GetThemeColor4ubv(TH_TITLE, r_color);
+ if (region_search_filter_active && !search_match) {
+ r_color[0] *= 0.5;
+ r_color[1] *= 0.5;
+ r_color[2] *= 0.5;
}
+}
- /* Draw the header backdrop. */
- if (show_background && !is_subpanel && !draw_box_style) {
- const float minx = rect->xmin;
- const float y = headrect.ymax;
-
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- GPU_blend(GPU_BLEND_ALPHA);
-
- /* Draw with background color. */
- immUniformThemeColor(UI_panel_matches_search_filter(panel) ? TH_MATCH : TH_PANEL_HEADER);
- immRectf(pos, minx, headrect.ymin, rect->xmax, y);
-
- immBegin(GPU_PRIM_LINES, 4);
-
- immVertex2f(pos, minx, y);
- immVertex2f(pos, rect->xmax, y);
+static void panel_draw_aligned_widgets(const uiStyle *style,
+ const Panel *panel,
+ const rcti *header_rect,
+ const float aspect,
+ const bool show_pin,
+ const bool show_background,
+ const bool region_search_filter_active)
+{
+ const bool is_subpanel = panel->type->parent != NULL;
+ const uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
- immVertex2f(pos, minx, y);
- immVertex2f(pos, rect->xmax, y);
+ const int header_height = BLI_rcti_size_y(header_rect);
+ const int scaled_unit = round_fl_to_int(UI_UNIT_X / aspect);
- immEnd();
+ /* Offset triangle and text to the right for subpanels. */
+ const rcti widget_rect = {
+ .xmin = header_rect->xmin + (is_subpanel ? scaled_unit * 0.7f : 0),
+ .xmax = header_rect->xmax,
+ .ymin = header_rect->ymin,
+ .ymax = header_rect->ymax,
+ };
- GPU_blend(GPU_BLEND_NONE);
- immUnbindProgram();
- }
-
- /* draw optional pin icon */
- if (show_pin && (block->panel->flag & PNL_PIN)) {
- uchar col_title[4];
- panel_title_color_get(panel, show_background, region_search_filter_active, col_title);
+ uchar title_color[4];
+ panel_title_color_get(panel, show_background, region_search_filter_active, title_color);
+ title_color[3] = 255;
+ /* Draw collapse icon. */
+ {
+ rctf collapse_rect = {
+ .xmin = widget_rect.xmin,
+ .xmax = widget_rect.xmin + header_height,
+ .ymin = widget_rect.ymin,
+ .ymax = widget_rect.ymax,
+ };
+ BLI_rctf_scale(&collapse_rect, 0.25f);
+
+ float triangle_color[4];
+ rgba_uchar_to_float(triangle_color, title_color);
+
+ ui_draw_anti_tria_rect(&collapse_rect, UI_panel_is_closed(panel) ? 'h' : 'v', triangle_color);
+ }
+
+ /* Draw text label. */
+ if (panel->drawname[0] != '\0') {
+ /* + 0.001f to avoid flirting with float inaccuracy .*/
+ const rcti title_rect = {
+ .xmin = widget_rect.xmin + panel->labelofs + scaled_unit * 1.1f,
+ .xmax = widget_rect.xmax,
+ .ymin = widget_rect.ymin - 2.0f / aspect,
+ .ymax = widget_rect.ymax,
+ };
+ UI_fontstyle_draw(fontstyle,
+ &title_rect,
+ panel->drawname,
+ title_color,
+ &(struct uiFontStyleDraw_Params){
+ .align = UI_STYLE_TEXT_LEFT,
+ });
+ }
+
+ /* Draw the pin icon. */
+ if (show_pin && (panel->flag & PNL_PIN)) {
GPU_blend(GPU_BLEND_ALPHA);
- UI_icon_draw_ex(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect),
- headrect.ymin + (5.0f / block->aspect),
- (panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED,
- (block->aspect * U.inv_dpi_fac),
+ UI_icon_draw_ex(widget_rect.xmax - scaled_unit * 2.2f,
+ widget_rect.ymin + 5.0f / aspect,
+ ICON_PINNED,
+ aspect * U.inv_dpi_fac,
1.0f,
0.0f,
- col_title,
+ title_color,
false);
GPU_blend(GPU_BLEND_NONE);
}
- /* Draw the title. */
- rcti titlerect = headrect;
- if (is_subpanel) {
- titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
- }
- ui_draw_aligned_panel_header(
- style, block, &titlerect, show_background, region_search_filter_active);
-
- if (show_drag) {
- /* Make `itemrect` smaller. */
- const float scale = 0.7;
- rctf itemrect;
- itemrect.xmax = headrect.xmax - (0.2f * UI_UNIT_X);
- itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect);
- itemrect.ymin = headrect.ymin;
- itemrect.ymax = headrect.ymax;
- BLI_rctf_scale(&itemrect, scale);
-
+ /* Draw drag widget. */
+ if (!is_subpanel) {
+ const int drag_widget_size = header_height * 0.7f;
GPU_matrix_push();
- GPU_matrix_translate_2f(itemrect.xmin, itemrect.ymin);
+ /* The magic numbers here center the widget vertically and offset it to the left.
+ * Currently this depends on the height of the header, although it could be independent. */
+ GPU_matrix_translate_2f(widget_rect.xmax - scaled_unit * 1.15,
+ widget_rect.ymin + (header_height - drag_widget_size) * 0.5f);
const int col_tint = 84;
- float col_high[4], col_dark[4];
- UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high);
- UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark);
+ float color_high[4], color_dark[4];
+ UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, color_high);
+ UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, color_dark);
GPUBatch *batch = GPU_batch_preset_panel_drag_widget(
- U.pixelsize, col_high, col_dark, BLI_rcti_size_y(&headrect) * scale);
+ U.pixelsize, color_high, color_dark, drag_widget_size);
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR);
GPU_batch_draw(batch);
GPU_matrix_pop();
}
+}
- /* Draw panel backdrop. */
- if (!UI_panel_is_closed(panel)) {
- /* in some occasions, draw a border */
- if (panel->flag & PNL_SELECT && !is_subpanel) {
- float radius;
- if (draw_box_style) {
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- radius = box_wcol->roundness * U.widget_unit;
+static void panel_draw_aligned_backdrop(const Panel *panel,
+ const rcti *rect,
+ const rcti *header_rect)
+{
+ const bool draw_box_style = panel->type->flag & PANEL_TYPE_DRAW_BOX;
+ const bool is_subpanel = panel->type->parent != NULL;
+ const bool is_open = !UI_panel_is_closed(panel);
+
+ if (is_subpanel && !is_open) {
+ return;
+ }
+
+ const uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ /* Draw with an opaque box backdrop for box style panels. */
+ if (draw_box_style) {
+ /* Use the theme for box widgets. */
+ const uiWidgetColors *box_wcol = &UI_GetTheme()->tui.wcol_box;
+
+ if (is_subpanel) {
+ /* Use rounded bottom corners for the last subpanel. */
+ if (panel->next == NULL) {
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
+ float color[4];
+ UI_GetThemeColor4fv(TH_PANEL_SUB_BACK, color);
+ /* Change the width a little bit to line up with sides. */
+ UI_draw_roundbox_aa(true,
+ rect->xmin + U.pixelsize,
+ rect->ymin + U.pixelsize,
+ rect->xmax - U.pixelsize,
+ rect->ymax,
+ box_wcol->roundness * U.widget_unit,
+ color);
}
else {
- UI_draw_roundbox_corner_set(UI_CNR_NONE);
- radius = 0.0f;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_PANEL_SUB_BACK);
+ immRectf(pos, rect->xmin + U.pixelsize, rect->ymin, rect->xmax - U.pixelsize, rect->ymax);
+ immUnbindProgram();
}
-
- UI_GetThemeColorShade4fv(TH_BACK, -120, color);
- UI_draw_roundbox_aa(false,
- 0.5f + rect->xmin,
- 0.5f + rect->ymin,
- 0.5f + rect->xmax,
- 0.5f + headrect.ymax + 1,
- radius,
- color);
}
-
+ else {
+ /* Expand the top a tiny bit to give header buttons equal size above and below. */
+ rcti box_rect = {
+ .xmin = rect->xmin,
+ .xmax = rect->xmax,
+ .ymin = is_open ? rect->ymin : header_rect->ymin,
+ .ymax = header_rect->ymax + U.pixelsize,
+ };
+ ui_draw_box_opaque(&box_rect, UI_CNR_ALL);
+
+ /* Mimic the border between aligned box widgets for the bottom of the header. */
+ if (is_open) {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ /* Top line. */
+ immUniformColor4ubv(box_wcol->outline);
+ immRectf(pos, rect->xmin, header_rect->ymin - U.pixelsize, rect->xmax, header_rect->ymin);
+
+ /* Bottom "shadow" line. */
+ immUniformThemeColor(TH_WIDGET_EMBOSS);
+ immRectf(pos,
+ rect->xmin,
+ header_rect->ymin - U.pixelsize,
+ rect->xmax,
+ header_rect->ymin - U.pixelsize - 1);
+
+ GPU_blend(GPU_BLEND_NONE);
+ immUnbindProgram();
+ }
+ }
+ }
+ else {
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
- /* Draw panel backdrop if it wasn't already been drawn by the single opaque round box earlier.
- * Note: Sub-panels blend with panels, so they can't be opaque. */
- if (show_background && !(draw_box_style && !is_subpanel)) {
- /* Draw the bottom sub-panels. */
- if (draw_box_style) {
- if (panel->next) {
- immUniformThemeColor(panel_col);
- immRectf(
- pos, rect->xmin + U.pixelsize, rect->ymin, rect->xmax - U.pixelsize, rect->ymax);
- }
- else {
- /* Change the width a little bit to line up with sides. */
- UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
- UI_GetThemeColor4fv(panel_col, color);
- UI_draw_roundbox_aa(true,
- rect->xmin + U.pixelsize,
- rect->ymin + U.pixelsize,
- rect->xmax - U.pixelsize,
- rect->ymax,
- box_wcol->roundness * U.widget_unit,
- color);
- }
- }
- else {
- immUniformThemeColor(panel_col);
- immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- }
+ /* Panel backdrop. */
+ if (is_open || panel->type->flag & PANEL_TYPE_NO_HEADER) {
+ immUniformThemeColor(is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
}
+ /* Panel header backdrops for non sub-panels. */
+ if (!is_subpanel) {
+ immUniformThemeColor(UI_panel_matches_search_filter(panel) ? TH_MATCH : TH_PANEL_HEADER);
+ immRectf(pos, rect->xmin, header_rect->ymin, rect->xmax, header_rect->ymax);
+ }
+
+ GPU_blend(GPU_BLEND_NONE);
immUnbindProgram();
}
+}
- /* Draw collapse icon. */
- {
- rctf itemrect = {.xmin = titlerect.xmin,
- .xmax = itemrect.xmin + BLI_rcti_size_y(&titlerect),
- .ymin = titlerect.ymin,
- .ymax = titlerect.ymax};
- BLI_rctf_scale(&itemrect, 0.25f);
-
- uchar col_title[4];
- panel_title_color_get(panel, show_background, region_search_filter_active, col_title);
- float tria_color[4];
- rgb_uchar_to_float(tria_color, col_title);
- tria_color[3] = 1.0f;
+/**
+ * Draw a panel integrated in buttons-window, tool/property lists etc.
+ */
+void ui_draw_aligned_panel(const uiStyle *style,
+ const uiBlock *block,
+ const rcti *rect,
+ const bool show_pin,
+ const bool show_background,
+ const bool region_search_filter_active)
+{
+ const Panel *panel = block->panel;
- if (UI_panel_is_closed(panel)) {
- ui_draw_anti_tria_rect(&itemrect, 'h', tria_color);
- }
- else {
- ui_draw_anti_tria_rect(&itemrect, 'v', tria_color);
- }
+ /* Add 0.001f to prevent flicker frpm float inaccuracy. */
+ const rcti header_rect = {
+ rect->xmin,
+ rect->xmax,
+ rect->ymax,
+ rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f),
+ };
+
+ if (show_background) {
+ panel_draw_aligned_backdrop(panel, rect, &header_rect);
+ }
+
+ /* Draw the widgets and text in the panel header. */
+ if (!(panel->type->flag & PANEL_TYPE_NO_HEADER)) {
+ panel_draw_aligned_widgets(style,
+ panel,
+ &header_rect,
+ block->aspect,
+ show_pin,
+ show_background,
+ region_search_filter_active);
}
}
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 4ad5d85e959..83e48fad157 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -447,6 +447,36 @@ bool ui_but_contains_password(const uiBut *but)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Button (#uiBut) Text
+ * \{ */
+
+size_t ui_but_drawstr_len_without_sep_char(const uiBut *but)
+{
+ if (but->flag & UI_BUT_HAS_SEP_CHAR) {
+ const char *str_sep = strrchr(but->drawstr, UI_SEP_CHAR);
+ if (str_sep != NULL) {
+ return (str_sep - but->drawstr);
+ }
+ }
+ return strlen(but->drawstr);
+}
+
+size_t ui_but_tip_len_only_first_line(const uiBut *but)
+{
+ if (but->tip == NULL) {
+ return 0;
+ }
+
+ const char *str_sep = strchr(but->tip, '\n');
+ if (str_sep != NULL) {
+ return (str_sep - but->tip);
+ }
+ return strlen(but->tip);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Block (#uiBlock) State
* \{ */
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index 1a9a663f94e..a9f72233cb1 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -416,7 +416,7 @@ void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap)
pup->window = window;
/* TODO(campbell): we may want to make this configurable.
- * The begin/end stype of calling popups doesn't allow to 'can_refresh' to be set.
+ * The begin/end stype of calling popups doesn't allow 'can_refresh' to be set.
* For now close this style of popovers when accessed. */
UI_block_flag_disable(pup->block, UI_BLOCK_KEEP_OPEN);
diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c
index 5aa61139468..6b46d43e5bf 100644
--- a/source/blender/editors/object/object_volume.c
+++ b/source/blender/editors/object/object_volume.c
@@ -60,7 +60,7 @@ static Object *object_volume_add(bContext *C, wmOperator *op, const char *name)
float loc[3], rot[3];
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
- return false;
+ return NULL;
}
return ED_object_add_type(C, OB_VOLUME, name, loc, rot, false, local_view_bits);
}
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index f0cf1f2fbf9..1d5903bf417 100644
--- a/source/blender/editors/physics/physics_pointcache.c
+++ b/source/blender/editors/physics/physics_pointcache.c
@@ -72,7 +72,7 @@ static bool ptcache_poll(bContext *C)
}
if (ID_IS_LINKED(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
- CTX_wm_operator_poll_msg_set(C, "Linked data-blocks do not allow to edit caches");
+ CTX_wm_operator_poll_msg_set(C, "Linked data-blocks do not allow editing caches");
return false;
}
@@ -92,7 +92,7 @@ static bool ptcache_add_remove_poll(bContext *C)
if (ID_IS_OVERRIDE_LIBRARY_REAL(id) || ID_IS_LINKED(id)) {
CTX_wm_operator_poll_msg_set(
- C, "Linked or library override data-blocks do not allow to add or remove caches");
+ C, "Linked or library override data-blocks do not allow adding or removing caches");
return false;
}
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 4dd7ecb09ca..11d897cf76f 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -531,7 +531,7 @@ static SculptGestureContext *sculpt_gesture_init_from_line(bContext *C, wmOperat
sgcontext, line_points, plane_points, offset_plane_points);
/* Calculate line plane and normal. */
- const bool flip = sgcontext->line.flip ^ !sgcontext->vc.rv3d->is_persp;
+ const bool flip = sgcontext->line.flip ^ (!sgcontext->vc.rv3d->is_persp);
sculpt_gesture_line_plane_from_tri(sgcontext->line.true_plane,
sgcontext,
flip,
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index c05dace380a..f67c8f701f7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -1213,7 +1213,7 @@ static bool sculpt_face_set_edit_is_operation_valid(SculptSession *ss,
{
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
/* Dyntopo is not supported. */
- return OPERATOR_CANCELLED;
+ return false;
}
if (mode == SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY) {
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index ae15b651059..09440ee7d98 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -2610,39 +2610,18 @@ typedef struct tEulerFilter {
const char *rna_path;
} tEulerFilter;
-static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
+/* Find groups of `rotation_euler` channels. */
+static ListBase /*tEulerFilter*/ euler_filter_group_channels(
+ const ListBase /*bAnimListElem*/ *anim_data, ReportList *reports, int *r_num_groups)
{
- bAnimContext ac;
-
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
- ListBase eulers = {NULL, NULL};
+ ListBase euler_groups = {NULL, NULL};
tEulerFilter *euf = NULL;
- int groups = 0, failed = 0;
-
- /* Get editor data. */
- if (ANIM_animdata_get_context(C, &ac) == 0) {
- return OPERATOR_CANCELLED;
- }
-
- /* The process is done in two passes:
- * 1) Sets of three related rotation curves are identified from the selected channels,
- * and are stored as a single 'operation unit' for the next step.
- * 2) Each set of three F-Curves is processed for each keyframe, with the values being
- * processed as necessary.
- */
-
- /* Step 1: extract only the rotation f-curves. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+ *r_num_groups = 0;
- for (ale = anim_data.first; ale; ale = ale->next) {
- FCurve *fcu = (FCurve *)ale->data;
+ LISTBASE_FOREACH (bAnimListElem *, ale, anim_data) {
+ FCurve *const fcu = (FCurve *)ale->data;
- /* Check if this is an appropriate F-Curve
+ /* Check if this is an appropriate F-Curve:
* - Only rotation curves.
* - For pchan curves, make sure we're only using the euler curves.
*/
@@ -2650,7 +2629,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
continue;
}
if (ELEM(fcu->array_index, 0, 1, 2) == 0) {
- BKE_reportf(op->reports,
+ BKE_reportf(reports,
RPT_WARNING,
"Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
(ale->id) ? ale->id->name : TIP_("<No ID>"),
@@ -2659,6 +2638,10 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
continue;
}
+ /* Assume that this animation channel will be touched by the Euler filter. Doing this here
+ * saves another loop over the animation data. */
+ ale->update |= ANIM_UPDATE_DEFAULT;
+
/* Optimization: assume that xyz curves will always be stored consecutively,
* so if the paths or the ID's don't match up, then a curve needs to be added
* to a new group.
@@ -2666,40 +2649,34 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) {
/* This should be fine to add to the existing group then. */
euf->fcurves[fcu->array_index] = fcu;
- }
- else {
- /* Just add to a new block. */
- euf = MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
- BLI_addtail(&eulers, euf);
- groups++;
-
- euf->id = ale->id;
- /* This should be safe, since we're only using it for a short time. */
- euf->rna_path = fcu->rna_path;
- euf->fcurves[fcu->array_index] = fcu;
+ continue;
}
- ale->update |= ANIM_UPDATE_DEFAULT;
- }
+ /* Just add to a new block. */
+ euf = MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
+ BLI_addtail(&euler_groups, euf);
+ ++*r_num_groups;
- if (groups == 0) {
- ANIM_animdata_freelist(&anim_data);
- BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
- return OPERATOR_CANCELLED;
+ euf->id = ale->id;
+ /* This should be safe, since we're only using it for a short time. */
+ euf->rna_path = fcu->rna_path;
+ euf->fcurves[fcu->array_index] = fcu;
}
- /* Step 2: go through each set of curves, processing the values at each keyframe.
- * - It is assumed that there must be a full set of keyframes at each keyframe position.
- */
- for (euf = eulers.first; euf; euf = euf->next) {
- int f;
+ return euler_groups;
+}
+
+static int euler_filter_perform_filter(ListBase /*tEulerFilter*/ *eulers, ReportList *reports)
+{
+ int failed = 0;
+ LISTBASE_FOREACH (tEulerFilter *, euf, eulers) {
/* Sanity check: ensure that there are enough F-Curves to work on in this group. */
/* TODO: also enforce assumption that there be a full set of keyframes
* at each position by ensuring that totvert counts are same? (Joshua Leung 2011) */
if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
/* Report which components are missing. */
- BKE_reportf(op->reports,
+ BKE_reportf(reports,
RPT_WARNING,
"Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
(euf->fcurves[0] == NULL) ? "X" : "",
@@ -2717,7 +2694,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
* keys of greater than 180 degrees as being a flip. */
/* FIXME: there are more complicated methods that
* will be needed to fix more cases than just some */
- for (f = 0; f < 3; f++) {
+ for (int f = 0; f < 3; f++) {
FCurve *fcu = euf->fcurves[f];
BezTriple *bezt, *prev;
uint i;
@@ -2732,21 +2709,62 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) {
const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f;
- /* > 180 degree flip? */
- if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
- /* 360 degrees to add/subtract frame value until difference
- * is acceptably small that there's no more flip. */
- const float fac = sign * 2.0f * (float)M_PI;
+ /* >= 180 degree flip? */
+ if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) < (float)M_PI) {
+ continue;
+ }
- while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
- bezt->vec[0][1] += fac;
- bezt->vec[1][1] += fac;
- bezt->vec[2][1] += fac;
- }
+ /* 360 degrees to add/subtract frame value until difference
+ * is acceptably small that there's no more flip. */
+ const float fac = sign * 2.0f * (float)M_PI;
+
+ while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
+ bezt->vec[0][1] += fac;
+ bezt->vec[1][1] += fac;
+ bezt->vec[2][1] += fac;
}
}
}
}
+
+ return failed;
+}
+
+static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
+{
+ /* Get editor data. */
+ bAnimContext ac;
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* The process is done in two passes:
+ * 1) Sets of three related rotation curves are identified from the selected channels,
+ * and are stored as a single 'operation unit' for the next step.
+ * 2) Each set of three F-Curves is processed for each keyframe, with the values being
+ * processed as necessary.
+ */
+
+ /* Step 1: extract only the rotation f-curves. */
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ int groups = 0;
+ ListBase eulers = euler_filter_group_channels(&anim_data, op->reports, &groups);
+ BLI_assert(BLI_listbase_count(&eulers) == groups);
+
+ if (groups == 0) {
+ ANIM_animdata_freelist(&anim_data);
+ BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Step 2: go through each set of curves, processing the values at each keyframe.
+ * - It is assumed that there must be a full set of keyframes at each keyframe position.
+ */
+ const int failed = euler_filter_perform_filter(&eulers, op->reports);
BLI_freelistN(&eulers);
ANIM_animdata_update(&ac, &anim_data);
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 2335bde33a7..2ce55040c69 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -1291,7 +1291,7 @@ static void node_draw_basis(const bContext *C,
}
/* body */
- if (!nodeIsRegistered(node)) {
+ if (nodeTypeUndefined(node)) {
/* use warning color to indicate undefined types */
UI_GetThemeColor4fv(TH_REDALERT, color);
}
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 5f3047fbdc2..5060ac0db8a 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -1281,7 +1281,7 @@ void NODE_OT_find_node(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Find Node";
- ot->description = "Search for named node and allow to select and activate it";
+ ot->description = "Search for a node by name and focus and select it";
ot->idname = "NODE_OT_find_node";
/* api callbacks */
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 670b58db0e0..e686648038d 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -346,7 +346,7 @@ void outliner_collection_delete(
/* Test in case collection got deleted as part of another one. */
if (BLI_findindex(&bmain->collections, collection) != -1) {
- /* We cannot allow to delete collections that are indirectly linked,
+ /* We cannot allow deleting collections that are indirectly linked,
* or that are used by (linked to...) other linked scene/collection. */
bool skip = false;
if (ID_IS_LINKED(collection)) {
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 7242d7e0002..ea2e3ce2565 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -3278,6 +3278,7 @@ static void outliner_draw_hierarchy_lines(SpaceOutliner *space_outliner,
UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col);
col[3] = 255;
+ GPU_line_width(1.0f);
GPU_blend(GPU_BLEND_ALPHA);
outliner_draw_hierarchy_lines_recursive(pos, space_outliner, lb, startx, col, false, starty);
GPU_blend(GPU_BLEND_NONE);
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index 2ee11f1abfd..e1c193b0c15 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SRC
sequencer_modifier.c
sequencer_ops.c
sequencer_preview.c
+ sequencer_proxy.c
sequencer_scopes.c
sequencer_select.c
sequencer_view.c
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index eb4a1601187..93b17830c0f 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -72,46 +72,6 @@
/** \name Structs & Enums
* \{ */
-/* RNA Enums, used in multiple files. */
-EnumPropertyItem sequencer_prop_effect_types[] = {
- {SEQ_TYPE_CROSS, "CROSS", 0, "Crossfade", "Crossfade effect strip type"},
- {SEQ_TYPE_ADD, "ADD", 0, "Add", "Add effect strip type"},
- {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", "Subtract effect strip type"},
- {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", "Alpha Over effect strip type"},
- {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", "Alpha Under effect strip type"},
- {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", "Gamma Cross effect strip type"},
- {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", "Multiply effect strip type"},
- {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Alpha Over Drop", "Alpha Over Drop effect strip type"},
- {SEQ_TYPE_WIPE, "WIPE", 0, "Wipe", "Wipe effect strip type"},
- {SEQ_TYPE_GLOW, "GLOW", 0, "Glow", "Glow effect strip type"},
- {SEQ_TYPE_TRANSFORM, "TRANSFORM", 0, "Transform", "Transform effect strip type"},
- {SEQ_TYPE_COLOR, "COLOR", 0, "Color", "Color effect strip type"},
- {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", "Color effect strip type"},
- {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
- {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
- {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
- {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
- {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
-#define SEQ_SIDE_MOUSE -1
-
-EnumPropertyItem prop_side_types[] = {
- {SEQ_SIDE_MOUSE, "MOUSE", 0, "Mouse Position", ""},
- {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
- {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
- {SEQ_SIDE_BOTH, "BOTH", 0, "Both", ""},
- {SEQ_SIDE_NO_CHANGE, "NO_CHANGE", 0, "No Change", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
-static const EnumPropertyItem prop_side_lr_types[] = {
- {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
- {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
typedef struct TransSeq {
int start, machine;
int startstill, endstill;
@@ -125,399 +85,6 @@ typedef struct TransSeq {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Proxy Job Manager
- * \{ */
-
-typedef struct ProxyBuildJob {
- struct Main *main;
- struct Depsgraph *depsgraph;
- Scene *scene;
- ListBase queue;
- int stop;
-} ProxyJob;
-
-static void proxy_freejob(void *pjv)
-{
- ProxyJob *pj = pjv;
-
- BLI_freelistN(&pj->queue);
-
- MEM_freeN(pj);
-}
-
-/* Only this runs inside thread. */
-static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
-{
- ProxyJob *pj = pjv;
- LinkData *link;
-
- for (link = pj->queue.first; link; link = link->next) {
- struct SeqIndexBuildContext *context = link->data;
-
- SEQ_proxy_rebuild(context, stop, do_update, progress);
-
- if (*stop) {
- pj->stop = 1;
- fprintf(stderr, "Canceling proxy rebuild on users request...\n");
- break;
- }
- }
-}
-
-static void proxy_endjob(void *pjv)
-{
- ProxyJob *pj = pjv;
- Editing *ed = BKE_sequencer_editing_get(pj->scene, false);
- LinkData *link;
-
- for (link = pj->queue.first; link; link = link->next) {
- SEQ_proxy_rebuild_finish(link->data, pj->stop);
- }
-
- BKE_sequencer_free_imbuf(pj->scene, &ed->seqbase, false);
-
- WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene);
-}
-
-static void seq_proxy_build_job(const bContext *C, ReportList *reports)
-{
- wmJob *wm_job;
- ProxyJob *pj;
- struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Scene *scene = CTX_data_scene(C);
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- ScrArea *area = CTX_wm_area(C);
- Sequence *seq;
- GSet *file_list;
-
- if (ed == NULL) {
- return;
- }
-
- wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- scene,
- "Building Proxies",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_SEQ_BUILD_PROXY);
-
- pj = WM_jobs_customdata_get(wm_job);
-
- if (!pj) {
- pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
-
- pj->depsgraph = depsgraph;
- pj->scene = scene;
- pj->main = CTX_data_main(C);
-
- WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
- WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob);
- }
-
- file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
- bool selected = false; /* Check for no selected strips */
-
- SEQ_CURRENT_BEGIN (ed, seq) {
- if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META) ||
- (seq->flag & SELECT) == 0) {
- continue;
- }
-
- selected = true;
- if (!(seq->flag & SEQ_USE_PROXY)) {
- BKE_reportf(reports, RPT_WARNING, "Proxy is not enabled for %s, skipping", seq->name);
- continue;
- }
- if (seq->strip->proxy->build_size_flags == 0) {
- BKE_reportf(reports, RPT_WARNING, "Resolution is not selected for %s, skipping", seq->name);
- continue;
- }
-
- bool success = SEQ_proxy_rebuild_context(
- pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
-
- if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) {
- BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping", seq->name);
- }
- }
- SEQ_CURRENT_END;
-
- if (!selected) {
- BKE_reportf(reports, RPT_WARNING, "Select movie or image strips");
- return;
- }
-
- BLI_gset_free(file_list, MEM_freeN);
-
- if (selected && !WM_jobs_is_running(wm_job)) {
- G.is_break = false;
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- }
-
- ED_area_tag_redraw(area);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sequence Query Utilities
- * \{ */
-
-void seq_rectf(Sequence *seq, rctf *rect)
-{
- rect->xmin = seq->startdisp;
- rect->xmax = seq->enddisp;
- rect->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM;
- rect->ymax = seq->machine + SEQ_STRIP_OFSTOP;
-}
-
-void boundbox_seq(Scene *scene, rctf *rect)
-{
- Sequence *seq;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- float min[2], max[2];
-
- if (ed == NULL) {
- return;
- }
-
- min[0] = SFRA;
- max[0] = EFRA + 1;
- min[1] = 0.0;
- max[1] = 8.0;
-
- seq = ed->seqbasep->first;
- while (seq) {
-
- if (min[0] > seq->startdisp - 1) {
- min[0] = seq->startdisp - 1;
- }
- if (max[0] < seq->enddisp + 1) {
- max[0] = seq->enddisp + 1;
- }
- if (max[1] < seq->machine + 2) {
- max[1] = seq->machine + 2;
- }
-
- seq = seq->next;
- }
-
- rect->xmin = min[0];
- rect->xmax = max[0];
- rect->ymin = min[1];
- rect->ymax = max[1];
-}
-
-static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
-{
- int mval[2];
- float mouseloc[2];
-
- mval[0] = mouse_x;
- mval[1] = 0;
-
- /* Choose the side based on which side of the current frame the mouse is on. */
- UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]);
-
- return mouseloc[0] > frame ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT;
-}
-
-Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel)
-{
- /* sel: 0==unselected, 1==selected, -1==don't care. */
- Sequence *seq;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
-
- if (ed == NULL) {
- return NULL;
- }
-
- if (sel > 0) {
- sel = SELECT;
- }
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if ((seq != test) && (test->machine == seq->machine) &&
- ((sel == -1) || (sel && (seq->flag & SELECT)) ||
- (sel == 0 && (seq->flag & SELECT) == 0))) {
- switch (lr) {
- case SEQ_SIDE_LEFT:
- if (test->startdisp == (seq->enddisp)) {
- return seq;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if (test->enddisp == (seq->startdisp)) {
- return seq;
- }
- break;
- }
- }
- }
- return NULL;
-}
-
-static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel)
-{
- /* sel: 0==unselected, 1==selected, -1==don't care. */
- Sequence *seq, *best_seq = NULL;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
-
- int dist, best_dist;
- best_dist = MAXFRAME * 2;
-
- if (ed == NULL) {
- return NULL;
- }
-
- seq = ed->seqbasep->first;
- while (seq) {
- if ((seq != test) && (test->machine == seq->machine) && (test->depth == seq->depth) &&
- ((sel == -1) || (sel == (seq->flag & SELECT)))) {
- dist = MAXFRAME * 2;
-
- switch (lr) {
- case SEQ_SIDE_LEFT:
- if (seq->enddisp <= test->startdisp) {
- dist = test->enddisp - seq->startdisp;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if (seq->startdisp >= test->enddisp) {
- dist = seq->startdisp - test->enddisp;
- }
- break;
- }
-
- if (dist == 0) {
- best_seq = seq;
- break;
- }
- if (dist < best_dist) {
- best_dist = dist;
- best_seq = seq;
- }
- }
- seq = seq->next;
- }
- return best_seq; /* Can be null. */
-}
-
-Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2])
-{
- Sequence *seq;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- float x, y;
- float pixelx;
- float handsize;
- float displen;
- *hand = SEQ_SIDE_NONE;
-
- if (ed == NULL) {
- return NULL;
- }
-
- pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
-
- UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
-
- seq = ed->seqbasep->first;
-
- while (seq) {
- if (seq->machine == (int)y) {
- /* Check for both normal strips, and strips that have been flipped horizontally. */
- if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) ||
- ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) {
- if (BKE_sequence_tx_test(seq)) {
-
- /* Clamp handles to defined size in pixel space. */
- handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx);
- displen = (float)abs(seq->startdisp - seq->enddisp);
-
- /* Don't even try to grab the handles of small strips. */
- if (displen / pixelx > 16) {
-
- /* Set the max value to handle to 1/3 of the total len when its
- * less than 28. This is important because otherwise selecting
- * handles happens even when you click in the middle. */
- if ((displen / 3) < 30 * pixelx) {
- handsize = displen / 3;
- }
- else {
- CLAMP(handsize, 7 * pixelx, 30 * pixelx);
- }
-
- if (handsize + seq->startdisp >= x) {
- *hand = SEQ_SIDE_LEFT;
- }
- else if (-handsize + seq->enddisp <= x) {
- *hand = SEQ_SIDE_RIGHT;
- }
- }
- }
- return seq;
- }
- }
- seq = seq->next;
- }
- return NULL;
-}
-
-static bool seq_is_parent(Sequence *par, Sequence *seq)
-{
- return ((par->seq1 == seq) || (par->seq2 == seq) || (par->seq3 == seq));
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Selection Utilities
- * \{ */
-
-void ED_sequencer_deselect_all(Scene *scene)
-{
- Sequence *seq;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
-
- if (ed == NULL) {
- return;
- }
-
- SEQ_CURRENT_BEGIN (ed, seq) {
- seq->flag &= ~SEQ_ALLSEL;
- }
- SEQ_CURRENT_END;
-}
-
-void recurs_sel_seq(Sequence *seqm)
-{
- Sequence *seq;
-
- seq = seqm->seqbase.first;
- while (seq) {
-
- if (seqm->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) {
- seq->flag &= ~SEQ_ALLSEL;
- }
- else if (seqm->flag & SELECT) {
- seq->flag |= SELECT;
- }
- else {
- seq->flag &= ~SEQ_ALLSEL;
- }
-
- if (seq->seqbase.first) {
- recurs_sel_seq(seq);
- }
-
- seq = seq->next;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Public Context Checks
* \{ */
@@ -563,428 +130,59 @@ bool ED_space_sequencer_check_show_strip(SpaceSeq *sseq)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Find Selected Strips as Inputs to an Effects Strip
+/** \name Shared Poll Functions
* \{ */
-int seq_effect_find_selected(Scene *scene,
- Sequence *activeseq,
- int type,
- Sequence **r_selseq1,
- Sequence **r_selseq2,
- Sequence **r_selseq3,
- const char **r_error_str)
+/* Operator functions. */
+bool sequencer_edit_poll(bContext *C)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq1 = NULL, *seq2 = NULL, *seq3 = NULL, *seq;
-
- *r_error_str = NULL;
-
- if (!activeseq) {
- seq2 = BKE_sequencer_active_get(scene);
- }
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SELECT) {
- if (seq->type == SEQ_TYPE_SOUND_RAM && BKE_sequence_effect_get_num_inputs(type) != 0) {
- *r_error_str = N_("Cannot apply effects to audio sequence strips");
- return 0;
- }
- if (!ELEM(seq, activeseq, seq2)) {
- if (seq2 == NULL) {
- seq2 = seq;
- }
- else if (seq1 == NULL) {
- seq1 = seq;
- }
- else if (seq3 == NULL) {
- seq3 = seq;
- }
- else {
- *r_error_str = N_("Cannot apply effect to more than 3 sequence strips");
- return 0;
- }
- }
- }
- }
-
- /* Make sequence selection a little bit more intuitive
- * for 3 strips: the last-strip should be seq3. */
- if (seq3 != NULL && seq2 != NULL) {
- Sequence *tmp = seq2;
- seq2 = seq3;
- seq3 = tmp;
- }
-
- switch (BKE_sequence_effect_get_num_inputs(type)) {
- case 0:
- *r_selseq1 = *r_selseq2 = *r_selseq3 = NULL;
- return 1; /* Success. */
- case 1:
- if (seq2 == NULL) {
- *r_error_str = N_("At least one selected sequence strip is needed");
- return 0;
- }
- if (seq1 == NULL) {
- seq1 = seq2;
- }
- if (seq3 == NULL) {
- seq3 = seq2;
- }
- ATTR_FALLTHROUGH;
- case 2:
- if (seq1 == NULL || seq2 == NULL) {
- *r_error_str = N_("2 selected sequence strips are needed");
- return 0;
- }
- if (seq3 == NULL) {
- seq3 = seq2;
- }
- break;
- }
-
- if (seq1 == NULL && seq2 == NULL && seq3 == NULL) {
- *r_error_str = N_("TODO: in what cases does this happen?");
- return 0;
- }
-
- *r_selseq1 = seq1;
- *r_selseq2 = seq2;
- *r_selseq3 = seq3;
-
- /* TODO(Richard): This function needs some refactoring, this is just quick hack for T73828. */
- if (BKE_sequence_effect_get_num_inputs(type) < 3) {
- *r_selseq3 = NULL;
- }
- if (BKE_sequence_effect_get_num_inputs(type) < 2) {
- *r_selseq2 = NULL;
- }
-
- return 1;
+ return (BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL);
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Delete Utilities
- * \{ */
-
-static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall)
+#if 0 /* UNUSED */
+bool sequencer_strip_poll(bContext *C)
{
- Sequence *seq, *seqn;
- Sequence *last_seq = BKE_sequencer_active_get(scene);
-
- seq = lb->first;
- while (seq) {
- seqn = seq->next;
- if ((seq->flag & flag) || deleteall) {
- BLI_remlink(lb, seq);
- if (seq == last_seq) {
- BKE_sequencer_active_set(scene, NULL);
- }
- if (seq->type == SEQ_TYPE_META) {
- recurs_del_seq_flag(scene, &seq->seqbase, flag, 1);
- }
- BKE_sequence_free(scene, seq, true);
- }
- seq = seqn;
- }
+ Editing *ed;
+ return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) &&
+ (ed->act_seq != NULL));
}
+#endif
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Split (Hard) Utility
- * \{ */
-
-static Sequence *split_seq_hard(
- Main *bmain, Scene *scene, Sequence *seq, ListBase *new_seq_list, int split_frame)
+bool sequencer_strip_has_path_poll(bContext *C)
{
- TransSeq ts;
- Sequence *seqn = NULL;
- bool skip_dup = false;
-
- /* Unlike soft-split, it's important to use the same value for both strips. */
- const bool is_end_exact = ((seq->start + seq->len) == split_frame);
-
- /* Backup values. */
- ts.start = seq->start;
- ts.machine = seq->machine;
- ts.startstill = seq->startstill;
- ts.endstill = seq->endstill;
- ts.startdisp = seq->startdisp;
- ts.enddisp = seq->enddisp;
- ts.startofs = seq->startofs;
- ts.endofs = seq->endofs;
- ts.anim_startofs = seq->anim_startofs;
- ts.anim_endofs = seq->anim_endofs;
- ts.len = seq->len;
-
- if (seq->type != SEQ_TYPE_META) {
- /* Precaution, needed because the length saved on-disk may not match the length saved in the
- * blend file, or our code may have minor differences reading file length between versions.
- * This causes hard-split to fail, see: T47862. */
- BKE_sequence_reload_new_file(bmain, scene, seq, true);
- BKE_sequence_calc(scene, seq);
- }
+ Editing *ed;
+ Sequence *seq;
+ return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) &&
+ ((seq = ed->act_seq) != NULL) && (SEQ_HAS_PATH(seq)));
+}
- /* First Strip. */
- /* Important to offset the start when 'split_frame == seq->start'
- * because we need at least one frame of content after start/end still have clipped it. */
- if ((seq->startstill) && (split_frame <= seq->start)) {
- /* Don't do funny things with METAs. */
- if (seq->type == SEQ_TYPE_META) {
- skip_dup = true;
- seq->startstill = seq->start - split_frame;
- }
- else {
- seq->start = split_frame - 1;
- seq->startstill = split_frame - seq->startdisp - 1;
- seq->anim_endofs += seq->len - 1;
- seq->endstill = 0;
- }
- }
- /* Normal strip. */
- else if ((is_end_exact == false) &&
- ((split_frame >= seq->start) && (split_frame <= (seq->start + seq->len)))) {
- seq->endofs = 0;
- seq->endstill = 0;
- seq->anim_endofs += (seq->start + seq->len) - split_frame;
- }
- /* Strips with extended stillframes. */
- else if ((is_end_exact == true) ||
- (((seq->start + seq->len) < split_frame) && (seq->endstill))) {
- seq->endstill -= seq->enddisp - split_frame;
- /* Don't do funny things with METAs. */
- if (seq->type == SEQ_TYPE_META) {
- skip_dup = true;
- }
+bool sequencer_view_preview_poll(bContext *C)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ Editing *ed = BKE_sequencer_editing_get(CTX_data_scene(C), false);
+ if (ed && sseq && (sseq->mainb == SEQ_DRAW_IMG_IMBUF)) {
+ return 1;
}
- BKE_sequence_reload_new_file(bmain, scene, seq, false);
- BKE_sequence_calc(scene, seq);
+ return 0;
+}
- if (!skip_dup) {
- /* Duplicate AFTER the first change. */
- seqn = BKE_sequence_dupli_recursive(
- scene, scene, new_seq_list, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
+bool sequencer_view_strips_poll(bContext *C)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq && ED_space_sequencer_check_show_strip(sseq)) {
+ return 1;
}
- if (seqn) {
- seqn->flag |= SELECT;
-
-#if 0
- is_end_exact = ((seqn->start + seqn->len) == split_frame);
-#endif
- /* Second Strip. */
- /* strips with extended stillframes. */
- if ((seqn->startstill) && (split_frame == seqn->start + 1)) {
- seqn->start = ts.start;
- seqn->startstill = ts.start - split_frame;
- seqn->anim_endofs = ts.anim_endofs;
- seqn->endstill = ts.endstill;
- }
-
- /* Normal strip. */
- else if ((is_end_exact == false) &&
- ((split_frame >= seqn->start) && (split_frame <= (seqn->start + seqn->len)))) {
- seqn->start = split_frame;
- seqn->startstill = 0;
- seqn->startofs = 0;
- seqn->endofs = ts.endofs;
- seqn->anim_startofs += split_frame - ts.start;
- seqn->anim_endofs = ts.anim_endofs;
- seqn->endstill = ts.endstill;
- }
-
- /* Strips with extended stillframes after. */
- else if ((is_end_exact == true) ||
- (((seqn->start + seqn->len) < split_frame) && (seqn->endstill))) {
- seqn->start = split_frame;
- seqn->startofs = 0;
- seqn->anim_startofs += ts.len - 1;
- seqn->endstill = ts.enddisp - split_frame - 1;
- seqn->startstill = 0;
- }
-
- BKE_sequence_reload_new_file(bmain, scene, seqn, false);
- BKE_sequence_calc(scene, seqn);
- BKE_sequence_invalidate_cache_in_range(scene, seq, seqn, SEQ_CACHE_ALL_TYPES);
- }
- return seqn;
+ return 0;
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Split (Soft) Utility
+/** \name Remove Gaps Operator
* \{ */
-static Sequence *split_seq_soft(
- Main *UNUSED(bmain), Scene *scene, Sequence *seq, ListBase *new_seq_list, int split_frame)
-{
- TransSeq ts;
- Sequence *seqn = NULL;
- bool skip_dup = false;
-
- bool is_end_exact = ((seq->start + seq->len) == split_frame);
-
- /* Backup values. */
- ts.start = seq->start;
- ts.machine = seq->machine;
- ts.startstill = seq->startstill;
- ts.endstill = seq->endstill;
- ts.startdisp = seq->startdisp;
- ts.enddisp = seq->enddisp;
- ts.startofs = seq->startofs;
- ts.endofs = seq->endofs;
- ts.anim_startofs = seq->anim_startofs;
- ts.anim_endofs = seq->anim_endofs;
- ts.len = seq->len;
-
- /* First Strip. */
- /* Strips with extended stillfames. */
- /* Important to offset the start when 'split_frame == seq->start'
- * because we need at least one frame of content after start/end still have clipped it. */
- if ((seq->startstill) && (split_frame <= seq->start)) {
- /* don't do funny things with METAs ... */
- if (seq->type == SEQ_TYPE_META) {
- skip_dup = true;
- seq->startstill = seq->start - split_frame;
- }
- else {
- seq->start = split_frame - 1;
- seq->startstill = split_frame - seq->startdisp - 1;
- seq->endofs = seq->len - 1;
- seq->endstill = 0;
- }
- }
- /* Normal strip. */
- else if ((is_end_exact == false) && (split_frame >= seq->start) &&
- (split_frame <= (seq->start + seq->len))) {
- seq->endofs = (seq->start + seq->len) - split_frame;
- }
- /* Strips with extended stillframes. */
- else if ((is_end_exact == true) ||
- (((seq->start + seq->len) < split_frame) && (seq->endstill))) {
- seq->endstill -= seq->enddisp - split_frame;
- /* Don't do funny things with METAs. */
- if (seq->type == SEQ_TYPE_META) {
- skip_dup = true;
- }
- }
-
- BKE_sequence_calc(scene, seq);
-
- if (!skip_dup) {
- /* Duplicate AFTER the first change. */
- seqn = BKE_sequence_dupli_recursive(
- scene, scene, new_seq_list, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
- }
-
- if (seqn) {
- seqn->flag |= SELECT;
-
- is_end_exact = ((seqn->start + seqn->len) == split_frame);
-
- /* Second Strip. */
- /* Strips with extended stillframes. */
- if ((seqn->startstill) && (split_frame == seqn->start + 1)) {
- seqn->start = ts.start;
- seqn->startstill = ts.start - split_frame;
- seqn->endofs = ts.endofs;
- seqn->endstill = ts.endstill;
- }
-
- /* Normal strip. */
- else if ((is_end_exact == false) && (split_frame >= seqn->start) &&
- (split_frame <= (seqn->start + seqn->len))) {
- seqn->startstill = 0;
- seqn->startofs = split_frame - ts.start;
- seqn->endofs = ts.endofs;
- seqn->endstill = ts.endstill;
- }
-
- /* Strips with extended stillframes. */
- else if ((is_end_exact == true) ||
- (((seqn->start + seqn->len) < split_frame) && (seqn->endstill))) {
- seqn->start = split_frame - ts.len + 1;
- seqn->startofs = ts.len - 1;
- seqn->endstill = ts.enddisp - split_frame - 1;
- seqn->startstill = 0;
- }
-
- BKE_sequence_calc(scene, seqn);
- BKE_sequence_invalidate_cache_in_range(scene, seq, seqn, SEQ_CACHE_ALL_TYPES);
- }
- return seqn;
-}
-
-/* Like duplicate, but only duplicate and split overlapping strips,
- * strips to the left of the split_frame are ignored and strips to the right
- * are moved to the end of slist.
- * We have to work on the same slist (not using a separate list), since
- * otherwise dupli_seq can't check for duplicate names properly and
- * may generate strips with the same name which will mess up animdata.
- */
-
-static bool split_seq_list(
- Main *bmain,
- Scene *scene,
- ListBase *slist,
- int split_frame,
- int channel,
- bool use_cursor_position,
- Sequence *(*split_seq)(Main *bmain, Scene *, Sequence *, ListBase *, int))
-
-{
- Sequence *seq, *seq_next_iter;
- Sequence *seq_first_new = NULL;
-
- seq = slist->first;
-
- while (seq && seq != seq_first_new) {
- seq_next_iter = seq->next; /* We need this because we may remove seq. */
- seq->tmp = NULL;
- if (use_cursor_position) {
- if (seq->machine == channel && seq->startdisp < split_frame && seq->enddisp > split_frame) {
- Sequence *seqn = split_seq(bmain, scene, seq, slist, split_frame);
- if (seqn) {
- if (seq_first_new == NULL) {
- seq_first_new = seqn;
- }
- }
- }
- }
- else {
- if (seq->flag & SELECT) {
- if (split_frame > seq->startdisp && split_frame < seq->enddisp) {
- Sequence *seqn = split_seq(bmain, scene, seq, slist, split_frame);
- if (seqn) {
- if (seq_first_new == NULL) {
- seq_first_new = seqn;
- }
- }
- }
- else if (seq->enddisp <= split_frame) {
- /* Pass. */
- }
- else if (seq->startdisp >= split_frame) {
- /* Move to tail. */
- BLI_remlink(slist, seq);
- BLI_addtail(slist, seq);
-
- if (seq_first_new == NULL) {
- seq_first_new = seq;
- }
- }
- }
- }
- seq = seq_next_iter;
- }
-
- return (seq_first_new != NULL);
-}
-
static bool sequence_offset_after_frame(Scene *scene, const int delta, const int timeline_frame)
{
Sequence *seq;
@@ -1018,79 +216,43 @@ static bool sequence_offset_after_frame(Scene *scene, const int delta, const int
return done;
}
-#if 0
-static void set_filter_seq(Scene *scene)
+void boundbox_seq(Scene *scene, rctf *rect)
{
Sequence *seq;
Editing *ed = BKE_sequencer_editing_get(scene, false);
+ float min[2], max[2];
if (ed == NULL) {
return;
}
- if (okee("Set Deinterlace") == 0) {
- return;
- }
-
- SEQ_CURRENT_BEGIN (ed, seq) {
- if (seq->flag & SELECT) {
- if (seq->type == SEQ_TYPE_MOVIE) {
- seq->flag |= SEQ_FILTERY;
- BKE_sequence_reload_new_file(bmain, scene, seq, false);
- BKE_sequence_calc(scene, seq);
- }
- }
- }
- SEQ_CURRENT_END;
-}
-#endif
-
-static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene)
-{
- Sequence *seq, *last_seq = BKE_sequencer_active_get(scene);
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX];
-
- if (last_seq == NULL) {
- return;
- }
+ min[0] = SFRA;
+ max[0] = EFRA + 1;
+ min[1] = 0.0;
+ max[1] = 8.0;
- BLI_strncpy(from, last_seq->strip->dir, sizeof(from));
- /* XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
- * return; */
+ seq = ed->seqbasep->first;
+ while (seq) {
- BLI_strncpy(to, from, sizeof(to));
- /* XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
- * return; */
+ if (min[0] > seq->startdisp - 1) {
+ min[0] = seq->startdisp - 1;
+ }
+ if (max[0] < seq->enddisp + 1) {
+ max[0] = seq->enddisp + 1;
+ }
+ if (max[1] < seq->machine + 2) {
+ max[1] = seq->machine + 2;
+ }
- if (STREQ(to, from)) {
- return;
+ seq = seq->next;
}
- SEQ_CURRENT_BEGIN (ed, seq) {
- if (seq->flag & SELECT) {
- if (STREQLEN(seq->strip->dir, from, strlen(from))) {
- printf("found %s\n", seq->strip->dir);
-
- /* Strip off the beginning. */
- stripped[0] = 0;
- BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX);
-
- /* New path. */
- BLI_snprintf(seq->strip->dir, sizeof(seq->strip->dir), "%s%s", to, stripped);
- printf("new %s\n", seq->strip->dir);
- }
- }
- }
- SEQ_CURRENT_END;
+ rect->xmin = min[0];
+ rect->xmax = max[0];
+ rect->ymin = min[1];
+ rect->ymax = max[1];
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Remove Gaps Operator
- * \{ */
-
static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1208,72 +370,6 @@ void SEQUENCER_OT_gap_insert(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Shared Poll Functions
- * \{ */
-
-#if 0
-static int seq_get_snaplimit(View2D *v2d)
-{
- /* fake mouse coords to get the snap value
- * a bit lazy but its only done once pre transform */
- float xmouse, ymouse, x;
- int mval[2] = {24, 0}; /* 24 screen px snap */
-
- UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse);
- x = xmouse;
- mval[0] = 0;
- UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse);
- return (int)(x - xmouse);
-}
-#endif
-
-/* Operator functions. */
-bool sequencer_edit_poll(bContext *C)
-{
- return (BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL);
-}
-
-#if 0 /* UNUSED */
-bool sequencer_strip_poll(bContext *C)
-{
- Editing *ed;
- return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) &&
- (ed->act_seq != NULL));
-}
-#endif
-
-bool sequencer_strip_has_path_poll(bContext *C)
-{
- Editing *ed;
- Sequence *seq;
- return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) &&
- ((seq = ed->act_seq) != NULL) && (SEQ_HAS_PATH(seq)));
-}
-
-bool sequencer_view_preview_poll(bContext *C)
-{
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- Editing *ed = BKE_sequencer_editing_get(CTX_data_scene(C), false);
- if (ed && sseq && (sseq->mainb == SEQ_DRAW_IMG_IMBUF)) {
- return 1;
- }
-
- return 0;
-}
-
-bool sequencer_view_strips_poll(bContext *C)
-{
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- if (sseq && ED_space_sequencer_check_show_strip(sseq)) {
- return 1;
- }
-
- return 0;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Snap Strips to the Current Frame Operator
* \{ */
@@ -2129,6 +1225,102 @@ void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot)
/** \name Reassign Inputs Operator
* \{ */
+int seq_effect_find_selected(Scene *scene,
+ Sequence *activeseq,
+ int type,
+ Sequence **r_selseq1,
+ Sequence **r_selseq2,
+ Sequence **r_selseq3,
+ const char **r_error_str)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq1 = NULL, *seq2 = NULL, *seq3 = NULL, *seq;
+
+ *r_error_str = NULL;
+
+ if (!activeseq) {
+ seq2 = BKE_sequencer_active_get(scene);
+ }
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (seq->flag & SELECT) {
+ if (seq->type == SEQ_TYPE_SOUND_RAM && BKE_sequence_effect_get_num_inputs(type) != 0) {
+ *r_error_str = N_("Cannot apply effects to audio sequence strips");
+ return 0;
+ }
+ if (!ELEM(seq, activeseq, seq2)) {
+ if (seq2 == NULL) {
+ seq2 = seq;
+ }
+ else if (seq1 == NULL) {
+ seq1 = seq;
+ }
+ else if (seq3 == NULL) {
+ seq3 = seq;
+ }
+ else {
+ *r_error_str = N_("Cannot apply effect to more than 3 sequence strips");
+ return 0;
+ }
+ }
+ }
+ }
+
+ /* Make sequence selection a little bit more intuitive
+ * for 3 strips: the last-strip should be seq3. */
+ if (seq3 != NULL && seq2 != NULL) {
+ Sequence *tmp = seq2;
+ seq2 = seq3;
+ seq3 = tmp;
+ }
+
+ switch (BKE_sequence_effect_get_num_inputs(type)) {
+ case 0:
+ *r_selseq1 = *r_selseq2 = *r_selseq3 = NULL;
+ return 1; /* Success. */
+ case 1:
+ if (seq2 == NULL) {
+ *r_error_str = N_("At least one selected sequence strip is needed");
+ return 0;
+ }
+ if (seq1 == NULL) {
+ seq1 = seq2;
+ }
+ if (seq3 == NULL) {
+ seq3 = seq2;
+ }
+ ATTR_FALLTHROUGH;
+ case 2:
+ if (seq1 == NULL || seq2 == NULL) {
+ *r_error_str = N_("2 selected sequence strips are needed");
+ return 0;
+ }
+ if (seq3 == NULL) {
+ seq3 = seq2;
+ }
+ break;
+ }
+
+ if (seq1 == NULL && seq2 == NULL && seq3 == NULL) {
+ *r_error_str = N_("TODO: in what cases does this happen?");
+ return 0;
+ }
+
+ *r_selseq1 = seq1;
+ *r_selseq2 = seq2;
+ *r_selseq3 = seq3;
+
+ /* TODO(Richard): This function needs some refactoring, this is just quick hack for T73828. */
+ if (BKE_sequence_effect_get_num_inputs(type) < 3) {
+ *r_selseq3 = NULL;
+ }
+ if (BKE_sequence_effect_get_num_inputs(type) < 2) {
+ *r_selseq2 = NULL;
+ }
+
+ return 1;
+}
+
static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -2242,10 +1434,19 @@ void SEQUENCER_OT_swap_inputs(struct wmOperatorType *ot)
/** \name Split Strips Operator
* \{ */
-enum {
- SEQ_SPLIT_SOFT,
- SEQ_SPLIT_HARD,
-};
+static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
+{
+ int mval[2];
+ float mouseloc[2];
+
+ mval[0] = mouse_x;
+ mval[1] = 0;
+
+ /* Choose the side based on which side of the current frame the mouse is on. */
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]);
+
+ return mouseloc[0] > frame ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT;
+}
static const EnumPropertyItem prop_split_types[] = {
{SEQ_SPLIT_SOFT, "SOFT", 0, "Soft", ""},
@@ -2253,42 +1454,44 @@ static const EnumPropertyItem prop_split_types[] = {
{0, NULL, 0, NULL, NULL},
};
+EnumPropertyItem prop_side_types[] = {
+ {SEQ_SIDE_MOUSE, "MOUSE", 0, "Mouse Position", ""},
+ {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
+ {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
+ {SEQ_SIDE_BOTH, "BOTH", 0, "Both", ""},
+ {SEQ_SIDE_NO_CHANGE, "NO_CHANGE", 0, "No Change", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
static int sequencer_split_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- int split_side, split_hard, split_frame, split_channel;
- bool changed, use_cursor_position, ignore_selection;
+ bool changed = false;
bool seq_selected = false;
- split_frame = RNA_int_get(op->ptr, "frame");
- split_channel = RNA_int_get(op->ptr, "channel");
- use_cursor_position = RNA_boolean_get(op->ptr, "use_cursor_position");
- split_hard = RNA_enum_get(op->ptr, "type");
- split_side = RNA_enum_get(op->ptr, "side");
- ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection");
+ const int split_frame = RNA_int_get(op->ptr, "frame");
+ const int split_channel = RNA_int_get(op->ptr, "channel");
+ const bool use_cursor_position = RNA_boolean_get(op->ptr, "use_cursor_position");
+ const eSeqSplitMethod method = RNA_enum_get(op->ptr, "type");
+ const int split_side = RNA_enum_get(op->ptr, "side");
+ const bool ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection");
BKE_sequencer_prefetch_stop(scene);
- if (split_hard == SEQ_SPLIT_HARD) {
- changed = split_seq_list(bmain,
- scene,
- ed->seqbasep,
- split_frame,
- split_channel,
- use_cursor_position,
- split_seq_hard);
- }
- else {
- changed = split_seq_list(bmain,
- scene,
- ed->seqbasep,
- split_frame,
- split_channel,
- use_cursor_position,
- split_seq_soft);
+ LISTBASE_FOREACH_BACKWARD (Sequence *, seq, ed->seqbasep) {
+ if (use_cursor_position && seq->machine != split_channel) {
+ continue;
+ }
+
+ if (ignore_selection || seq->flag & SELECT) {
+ if (SEQ_edit_strip_split(bmain, scene, ed->seqbasep, seq, split_frame, method) != NULL) {
+ changed = true;
+ }
+ }
}
+
if (changed) { /* Got new strips? */
Sequence *seq;
if (ignore_selection) {
@@ -2326,12 +1529,6 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
SEQ_CURRENT_END;
}
}
- SEQ_CURRENT_BEGIN (ed, seq) {
- if (seq->seq1 || seq->seq2 || seq->seq3) {
- BKE_sequence_calc(scene, seq);
- }
- }
- SEQ_CURRENT_END;
BKE_sequencer_sort(scene);
}
@@ -2464,8 +1661,6 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-#undef SEQ_SIDE_MOUSE
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -2757,6 +1952,31 @@ void SEQUENCER_OT_images_separate(wmOperatorType *ot)
/** \name Toggle Meta Strip Operator
* \{ */
+void recurs_sel_seq(Sequence *seqm)
+{
+ Sequence *seq;
+
+ seq = seqm->seqbase.first;
+ while (seq) {
+
+ if (seqm->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
+ else if (seqm->flag & SELECT) {
+ seq->flag |= SELECT;
+ }
+ else {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
+
+ if (seq->seqbase.first) {
+ recurs_sel_seq(seq);
+ }
+
+ seq = seq->next;
+ }
+}
+
static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -2937,6 +2157,28 @@ static int seq_depends_on_meta(Sequence *seq, Sequence *seqm)
return 0;
}
+static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall)
+{
+ Sequence *seq, *seqn;
+ Sequence *last_seq = BKE_sequencer_active_get(scene);
+
+ seq = lb->first;
+ while (seq) {
+ seqn = seq->next;
+ if ((seq->flag & flag) || deleteall) {
+ BLI_remlink(lb, seq);
+ if (seq == last_seq) {
+ BKE_sequencer_active_set(scene, NULL);
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ recurs_del_seq_flag(scene, &seq->seqbase, flag, 1);
+ }
+ BKE_sequence_free(scene, seq, true);
+ }
+ seq = seqn;
+ }
+}
+
static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -3082,6 +2324,12 @@ void SEQUENCER_OT_strip_jump(wmOperatorType *ot)
/** \name Swap Strip Operator
* \{ */
+static const EnumPropertyItem prop_side_lr_types[] = {
+ {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
+ {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb)
{
int gap = seqb->startdisp - seqa->enddisp;
@@ -3097,27 +2345,56 @@ static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb)
BKE_sequence_calc(scene, seqa);
}
-#if 0
-static Sequence *sequence_find_parent(Scene *scene, Sequence *child)
+static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel)
{
+ /* sel: 0==unselected, 1==selected, -1==don't care. */
+ Sequence *seq, *best_seq = NULL;
Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *parent = NULL;
- Sequence *seq;
+
+ int dist, best_dist;
+ best_dist = MAXFRAME * 2;
if (ed == NULL) {
return NULL;
}
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if ((seq != child) && seq_is_parent(seq, child)) {
- parent = seq;
- break;
+ seq = ed->seqbasep->first;
+ while (seq) {
+ if ((seq != test) && (test->machine == seq->machine) && (test->depth == seq->depth) &&
+ ((sel == -1) || (sel == (seq->flag & SELECT)))) {
+ dist = MAXFRAME * 2;
+
+ switch (lr) {
+ case SEQ_SIDE_LEFT:
+ if (seq->enddisp <= test->startdisp) {
+ dist = test->enddisp - seq->startdisp;
+ }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if (seq->startdisp >= test->enddisp) {
+ dist = seq->startdisp - test->enddisp;
+ }
+ break;
+ }
+
+ if (dist == 0) {
+ best_seq = seq;
+ break;
+ }
+ if (dist < best_dist) {
+ best_dist = dist;
+ best_seq = seq;
+ }
}
+ seq = seq->next;
}
+ return best_seq; /* Can be null. */
+}
- return parent;
+static bool seq_is_parent(Sequence *par, Sequence *seq)
+{
+ return ((par->seq1 == seq) || (par->seq2 == seq) || (par->seq3 == seq));
}
-#endif
static int sequencer_swap_exec(bContext *C, wmOperator *op)
{
@@ -3342,6 +2619,21 @@ void SEQUENCER_OT_copy(wmOperatorType *ot)
/** \name Paste Operator
* \{ */
+void ED_sequencer_deselect_all(Scene *scene)
+{
+ Sequence *seq;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ if (ed == NULL) {
+ return;
+ }
+
+ SEQ_CURRENT_BEGIN (ed, seq) {
+ seq->flag &= ~SEQ_ALLSEL;
+ }
+ SEQ_CURRENT_END;
+}
+
static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
@@ -3472,177 +2764,6 @@ void SEQUENCER_OT_swap_data(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Rebuild Proxy and Timecode Indices Operator
- * \{ */
-
-static int sequencer_rebuild_proxy_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- seq_proxy_build_job(C, op->reports);
-
- return OPERATOR_FINISHED;
-}
-
-static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq;
- GSet *file_list;
-
- if (ed == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
-
- SEQ_CURRENT_BEGIN (ed, seq) {
- if ((seq->flag & SELECT)) {
- ListBase queue = {NULL, NULL};
- LinkData *link;
- short stop = 0, do_update;
- float progress;
-
- SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue);
-
- for (link = queue.first; link; link = link->next) {
- struct SeqIndexBuildContext *context = link->data;
- SEQ_proxy_rebuild(context, &stop, &do_update, &progress);
- SEQ_proxy_rebuild_finish(context, 0);
- }
- BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
- }
- }
- SEQ_CURRENT_END;
-
- BLI_gset_free(file_list, MEM_freeN);
-
- return OPERATOR_FINISHED;
-}
-
-void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Rebuild Proxy and Timecode Indices";
- ot->idname = "SEQUENCER_OT_rebuild_proxy";
- ot->description = "Rebuild all selected proxies and timecode indices using the job system";
-
- /* Api callbacks. */
- ot->invoke = sequencer_rebuild_proxy_invoke;
- ot->exec = sequencer_rebuild_proxy_exec;
-
- /* Flags. */
- ot->flag = OPTYPE_REGISTER;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Set Selected Strip Proxies Operator
- * \{ */
-
-static int sequencer_enable_proxies_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- return WM_operator_props_dialog_popup(C, op, 200);
-}
-
-static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq;
- bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25");
- bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50");
- bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75");
- bool proxy_100 = RNA_boolean_get(op->ptr, "proxy_100");
- bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
- bool turnon = true;
-
- if (ed == NULL || !(proxy_25 || proxy_50 || proxy_75 || proxy_100)) {
- turnon = false;
- }
-
- SEQ_CURRENT_BEGIN (ed, seq) {
- if ((seq->flag & SELECT)) {
- if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META)) {
- SEQ_proxy_set(seq, turnon);
- if (seq->strip->proxy == NULL) {
- continue;
- }
-
- if (proxy_25) {
- seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_25;
- }
- else {
- seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_25;
- }
-
- if (proxy_50) {
- seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_50;
- }
- else {
- seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_50;
- }
-
- if (proxy_75) {
- seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_75;
- }
- else {
- seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_75;
- }
-
- if (proxy_100) {
- seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_100;
- }
- else {
- seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_100;
- }
-
- if (!overwrite) {
- seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
- }
- else {
- seq->strip->proxy->build_flags &= ~SEQ_PROXY_SKIP_EXISTING;
- }
- }
- }
- }
- SEQ_CURRENT_END;
-
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
-
- return OPERATOR_FINISHED;
-}
-
-void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Selected Strip Proxies";
- ot->idname = "SEQUENCER_OT_enable_proxies";
- ot->description = "Enable selected proxies on all selected Movie, Image and Meta strips";
-
- /* Api callbacks. */
- ot->invoke = sequencer_enable_proxies_invoke;
- ot->exec = sequencer_enable_proxies_exec;
-
- /* Flags. */
- ot->flag = OPTYPE_REGISTER;
-
- RNA_def_boolean(ot->srna, "proxy_25", false, "25%", "");
- RNA_def_boolean(ot->srna, "proxy_50", false, "50%", "");
- RNA_def_boolean(ot->srna, "proxy_75", false, "75%", "");
- RNA_def_boolean(ot->srna, "proxy_100", false, "100%", "");
- RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite", "");
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Change Effect Input Operator
* \{ */
@@ -3715,6 +2836,28 @@ void SEQUENCER_OT_change_effect_input(struct wmOperatorType *ot)
/** \name Change Effect Type Operator
* \{ */
+EnumPropertyItem sequencer_prop_effect_types[] = {
+ {SEQ_TYPE_CROSS, "CROSS", 0, "Crossfade", "Crossfade effect strip type"},
+ {SEQ_TYPE_ADD, "ADD", 0, "Add", "Add effect strip type"},
+ {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", "Subtract effect strip type"},
+ {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", "Alpha Over effect strip type"},
+ {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", "Alpha Under effect strip type"},
+ {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", "Gamma Cross effect strip type"},
+ {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", "Multiply effect strip type"},
+ {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Alpha Over Drop", "Alpha Over Drop effect strip type"},
+ {SEQ_TYPE_WIPE, "WIPE", 0, "Wipe", "Wipe effect strip type"},
+ {SEQ_TYPE_GLOW, "GLOW", 0, "Glow", "Glow effect strip type"},
+ {SEQ_TYPE_TRANSFORM, "TRANSFORM", 0, "Transform", "Transform effect strip type"},
+ {SEQ_TYPE_COLOR, "COLOR", 0, "Color", "Color effect strip type"},
+ {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", "Color effect strip type"},
+ {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
+ {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
+ {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
+ {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
+ {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -4139,3 +3282,220 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unused functions
+ * \{ */
+
+#if 0
+static void set_filter_seq(Scene *scene)
+{
+ Sequence *seq;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ if (ed == NULL) {
+ return;
+ }
+
+ if (okee("Set Deinterlace") == 0) {
+ return;
+ }
+
+ SEQ_CURRENT_BEGIN (ed, seq) {
+ if (seq->flag & SELECT) {
+ if (seq->type == SEQ_TYPE_MOVIE) {
+ seq->flag |= SEQ_FILTERY;
+ BKE_sequence_reload_new_file(bmain, scene, seq, false);
+ BKE_sequence_calc(scene, seq);
+ }
+ }
+ }
+ SEQ_CURRENT_END;
+}
+
+static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene)
+{
+ Sequence *seq, *last_seq = BKE_sequencer_active_get(scene);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX];
+
+ if (last_seq == NULL) {
+ return;
+ }
+
+ BLI_strncpy(from, last_seq->strip->dir, sizeof(from));
+ /* XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
+ * return; */
+
+ BLI_strncpy(to, from, sizeof(to));
+ /* XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
+ * return; */
+
+ if (STREQ(to, from)) {
+ return;
+ }
+
+ SEQ_CURRENT_BEGIN (ed, seq) {
+ if (seq->flag & SELECT) {
+ if (STREQLEN(seq->strip->dir, from, strlen(from))) {
+ printf("found %s\n", seq->strip->dir);
+
+ /* Strip off the beginning. */
+ stripped[0] = 0;
+ BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX);
+
+ /* New path. */
+ BLI_snprintf(seq->strip->dir, sizeof(seq->strip->dir), "%s%s", to, stripped);
+ printf("new %s\n", seq->strip->dir);
+ }
+ }
+ }
+ SEQ_CURRENT_END;
+}
+
+static Sequence *sequence_find_parent(Scene *scene, Sequence *child)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *parent = NULL;
+ Sequence *seq;
+
+ if (ed == NULL) {
+ return NULL;
+ }
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if ((seq != child) && seq_is_parent(seq, child)) {
+ parent = seq;
+ break;
+ }
+ }
+
+ return parent;
+}
+
+static int seq_get_snaplimit(View2D *v2d)
+{
+ /* fake mouse coords to get the snap value
+ * a bit lazy but its only done once pre transform */
+ float xmouse, ymouse, x;
+ int mval[2] = {24, 0}; /* 24 screen px snap */
+
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse);
+ x = xmouse;
+ mval[0] = 0;
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse);
+ return (int)(x - xmouse);
+}
+
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unused in current file
+ * \{ */
+
+void seq_rectf(Sequence *seq, rctf *rect)
+{
+ rect->xmin = seq->startdisp;
+ rect->xmax = seq->enddisp;
+ rect->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM;
+ rect->ymax = seq->machine + SEQ_STRIP_OFSTOP;
+}
+
+Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel)
+{
+ /* sel: 0==unselected, 1==selected, -1==don't care. */
+ Sequence *seq;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ if (ed == NULL) {
+ return NULL;
+ }
+
+ if (sel > 0) {
+ sel = SELECT;
+ }
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if ((seq != test) && (test->machine == seq->machine) &&
+ ((sel == -1) || (sel && (seq->flag & SELECT)) ||
+ (sel == 0 && (seq->flag & SELECT) == 0))) {
+ switch (lr) {
+ case SEQ_SIDE_LEFT:
+ if (test->startdisp == (seq->enddisp)) {
+ return seq;
+ }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if (test->enddisp == (seq->startdisp)) {
+ return seq;
+ }
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+
+Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2])
+{
+ Sequence *seq;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ float x, y;
+ float pixelx;
+ float handsize;
+ float displen;
+ *hand = SEQ_SIDE_NONE;
+
+ if (ed == NULL) {
+ return NULL;
+ }
+
+ pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
+
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
+
+ seq = ed->seqbasep->first;
+
+ while (seq) {
+ if (seq->machine == (int)y) {
+ /* Check for both normal strips, and strips that have been flipped horizontally. */
+ if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) ||
+ ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) {
+ if (BKE_sequence_tx_test(seq)) {
+
+ /* Clamp handles to defined size in pixel space. */
+ handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx);
+ displen = (float)abs(seq->startdisp - seq->enddisp);
+
+ /* Don't even try to grab the handles of small strips. */
+ if (displen / pixelx > 16) {
+
+ /* Set the max value to handle to 1/3 of the total len when its
+ * less than 28. This is important because otherwise selecting
+ * handles happens even when you click in the middle. */
+ if ((displen / 3) < 30 * pixelx) {
+ handsize = displen / 3;
+ }
+ else {
+ CLAMP(handsize, 7 * pixelx, 30 * pixelx);
+ }
+
+ if (handsize + seq->startdisp >= x) {
+ *hand = SEQ_SIDE_LEFT;
+ }
+ else if (-handsize + seq->enddisp <= x) {
+ *hand = SEQ_SIDE_RIGHT;
+ }
+ }
+ }
+ return seq;
+ }
+ }
+ seq = seq->next;
+ }
+ return NULL;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c
new file mode 100644
index 00000000000..2d23520814a
--- /dev/null
+++ b/source/blender/editors/space_sequencer/sequencer_proxy.c
@@ -0,0 +1,355 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spseq
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_timecode.h"
+
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "SEQ_sequencer.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_define.h"
+
+/* For menu, popup, icons, etc. */
+#include "ED_screen.h"
+
+/* Own include. */
+#include "sequencer_intern.h"
+
+/*--------------------------------------------------------------------*/
+/** \name Proxy Job Manager
+ * \{ */
+
+typedef struct ProxyBuildJob {
+ struct Main *main;
+ struct Depsgraph *depsgraph;
+ Scene *scene;
+ ListBase queue;
+ int stop;
+} ProxyJob;
+
+static void proxy_freejob(void *pjv)
+{
+ ProxyJob *pj = pjv;
+
+ BLI_freelistN(&pj->queue);
+
+ MEM_freeN(pj);
+}
+
+/* Only this runs inside thread. */
+static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
+{
+ ProxyJob *pj = pjv;
+ LinkData *link;
+
+ for (link = pj->queue.first; link; link = link->next) {
+ struct SeqIndexBuildContext *context = link->data;
+
+ SEQ_proxy_rebuild(context, stop, do_update, progress);
+
+ if (*stop) {
+ pj->stop = 1;
+ fprintf(stderr, "Canceling proxy rebuild on users request...\n");
+ break;
+ }
+ }
+}
+
+static void proxy_endjob(void *pjv)
+{
+ ProxyJob *pj = pjv;
+ Editing *ed = BKE_sequencer_editing_get(pj->scene, false);
+ LinkData *link;
+
+ for (link = pj->queue.first; link; link = link->next) {
+ SEQ_proxy_rebuild_finish(link->data, pj->stop);
+ }
+
+ BKE_sequencer_free_imbuf(pj->scene, &ed->seqbase, false);
+
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene);
+}
+
+static void seq_proxy_build_job(const bContext *C, ReportList *reports)
+{
+ wmJob *wm_job;
+ ProxyJob *pj;
+ struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ ScrArea *area = CTX_wm_area(C);
+ Sequence *seq;
+ GSet *file_list;
+
+ if (ed == NULL) {
+ return;
+ }
+
+ wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Building Proxies",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_SEQ_BUILD_PROXY);
+
+ pj = WM_jobs_customdata_get(wm_job);
+
+ if (!pj) {
+ pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
+
+ pj->depsgraph = depsgraph;
+ pj->scene = scene;
+ pj->main = CTX_data_main(C);
+
+ WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
+ WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob);
+ }
+
+ file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+ bool selected = false; /* Check for no selected strips */
+
+ SEQ_CURRENT_BEGIN (ed, seq) {
+ if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META) ||
+ (seq->flag & SELECT) == 0) {
+ continue;
+ }
+
+ selected = true;
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ BKE_reportf(reports, RPT_WARNING, "Proxy is not enabled for %s, skipping", seq->name);
+ continue;
+ }
+ if (seq->strip->proxy->build_size_flags == 0) {
+ BKE_reportf(reports, RPT_WARNING, "Resolution is not selected for %s, skipping", seq->name);
+ continue;
+ }
+
+ bool success = SEQ_proxy_rebuild_context(
+ pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+
+ if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) {
+ BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping", seq->name);
+ }
+ }
+ SEQ_CURRENT_END;
+
+ if (!selected) {
+ BKE_reportf(reports, RPT_WARNING, "Select movie or image strips");
+ return;
+ }
+
+ BLI_gset_free(file_list, MEM_freeN);
+
+ if (selected && !WM_jobs_is_running(wm_job)) {
+ G.is_break = false;
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+
+ ED_area_tag_redraw(area);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rebuild Proxy and Timecode Indices Operator
+ * \{ */
+
+static int sequencer_rebuild_proxy_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ seq_proxy_build_job(C, op->reports);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+ GSet *file_list;
+
+ if (ed == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+
+ SEQ_CURRENT_BEGIN (ed, seq) {
+ if ((seq->flag & SELECT)) {
+ ListBase queue = {NULL, NULL};
+ LinkData *link;
+ short stop = 0, do_update;
+ float progress;
+
+ SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue);
+
+ for (link = queue.first; link; link = link->next) {
+ struct SeqIndexBuildContext *context = link->data;
+ SEQ_proxy_rebuild(context, &stop, &do_update, &progress);
+ SEQ_proxy_rebuild_finish(context, 0);
+ }
+ BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
+ }
+ }
+ SEQ_CURRENT_END;
+
+ BLI_gset_free(file_list, MEM_freeN);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Rebuild Proxy and Timecode Indices";
+ ot->idname = "SEQUENCER_OT_rebuild_proxy";
+ ot->description = "Rebuild all selected proxies and timecode indices using the job system";
+
+ /* Api callbacks. */
+ ot->invoke = sequencer_rebuild_proxy_invoke;
+ ot->exec = sequencer_rebuild_proxy_exec;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Selected Strip Proxies Operator
+ * \{ */
+
+static int sequencer_enable_proxies_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ return WM_operator_props_dialog_popup(C, op, 200);
+}
+
+static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+ bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25");
+ bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50");
+ bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75");
+ bool proxy_100 = RNA_boolean_get(op->ptr, "proxy_100");
+ bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
+ bool turnon = true;
+
+ if (ed == NULL || !(proxy_25 || proxy_50 || proxy_75 || proxy_100)) {
+ turnon = false;
+ }
+
+ SEQ_CURRENT_BEGIN (ed, seq) {
+ if ((seq->flag & SELECT)) {
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META)) {
+ SEQ_proxy_set(seq, turnon);
+ if (seq->strip->proxy == NULL) {
+ continue;
+ }
+
+ if (proxy_25) {
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_25;
+ }
+ else {
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_25;
+ }
+
+ if (proxy_50) {
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_50;
+ }
+ else {
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_50;
+ }
+
+ if (proxy_75) {
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_75;
+ }
+ else {
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_75;
+ }
+
+ if (proxy_100) {
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_100;
+ }
+ else {
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_100;
+ }
+
+ if (!overwrite) {
+ seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
+ }
+ else {
+ seq->strip->proxy->build_flags &= ~SEQ_PROXY_SKIP_EXISTING;
+ }
+ }
+ }
+ }
+ SEQ_CURRENT_END;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Selected Strip Proxies";
+ ot->idname = "SEQUENCER_OT_enable_proxies";
+ ot->description = "Enable selected proxies on all selected Movie, Image and Meta strips";
+
+ /* Api callbacks. */
+ ot->invoke = sequencer_enable_proxies_invoke;
+ ot->exec = sequencer_enable_proxies_exec;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER;
+
+ RNA_def_boolean(ot->srna, "proxy_25", false, "25%", "");
+ RNA_def_boolean(ot->srna, "proxy_50", false, "50%", "");
+ RNA_def_boolean(ot->srna, "proxy_75", false, "75%", "");
+ RNA_def_boolean(ot->srna, "proxy_100", false, "100%", "");
+ RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite", "");
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 5ae012ce5dd..9f31e7a411d 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -468,7 +468,7 @@ static ID *view3d_drop_id_in_main_region_poll_id(bContext *C,
{
ScrArea *area = CTX_wm_area(C);
if (ED_region_overlap_isect_any_xy(area, &event->x)) {
- return false;
+ return NULL;
}
return WM_drag_ID(drag, id_type);
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 8a7ec7a99e9..5b41f6b51bf 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -506,7 +506,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
short orient_types[3];
float custom_matrix[3][3];
- short orient_type_default = V3D_ORIENT_GLOBAL;
short orient_type_scene = V3D_ORIENT_GLOBAL;
short orient_type_set = V3D_ORIENT_GLOBAL;
short orient_type_matrix_set = -1;
@@ -520,6 +519,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ short orient_type_default = orient_type_scene;
+
if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
}
@@ -535,7 +536,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
orient_type_default = orient_type_set;
}
else if (t->con.mode & CON_APPLY) {
- orient_type_set = orient_type_default = orient_type_scene;
+ orient_type_set = orient_type_scene;
}
else {
if (orient_type_set == orient_type_scene) {
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 69dfc4a7ad4..b353dba9e54 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -572,7 +572,7 @@ short ED_transform_calc_orientation_from_type_ex(const bContext *C,
TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
scene, orientation_index_custom);
applyTransformOrientation(custom_orientation, r_mat, NULL);
- break;
+ return V3D_ORIENT_CUSTOM + orientation_index_custom;
}
}
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
index ddca05bedc5..8a8259d335a 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -249,11 +249,19 @@ struct FaceIsland {
struct SharedUVLoopData {
uint cd_loop_uv_offset;
+ bool use_seams;
};
static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, void *user_data)
{
const struct SharedUVLoopData *data = user_data;
+
+ if (data->use_seams) {
+ if (BM_elem_flag_test(l_a->e, BM_ELEM_SEAM)) {
+ return false;
+ }
+ }
+
return BM_loop_uv_share_edge_check((BMLoop *)l_a, (BMLoop *)l_b, data->cd_loop_uv_offset);
}
@@ -265,6 +273,7 @@ static int bm_mesh_calc_uv_islands(const Scene *scene,
ListBase *island_list,
const bool only_selected_faces,
const bool only_selected_uvs,
+ const bool use_seams,
const float aspect_y,
const uint cd_loop_uv_offset)
{
@@ -273,6 +282,7 @@ static int bm_mesh_calc_uv_islands(const Scene *scene,
struct SharedUVLoopData user_data = {
.cd_loop_uv_offset = cd_loop_uv_offset,
+ .use_seams = use_seams,
};
int *groups_array = MEM_mallocN(sizeof(*groups_array) * (size_t)bm->totface, __func__);
@@ -377,6 +387,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
&island_list,
params->only_selected_faces,
params->only_selected_uvs,
+ params->use_seams,
aspect_y,
cd_loop_uv_offset);
}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index cc6eb49f984..ed9e5053f10 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -895,7 +895,7 @@ static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
return P_FALSE;
}
-static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool impl, PEdge **r_pair)
+static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool topology_from_uvs, PEdge **r_pair)
{
PHashKey key;
PEdge *pe;
@@ -920,7 +920,8 @@ static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool impl, PEdge **r_pa
((v1->u.key == key2) && (v2->u.key == key1))) {
/* don't connect seams and t-junctions */
- if ((pe->flag & PEDGE_SEAM) || *r_pair || (impl && p_edge_implicit_seam(e, pe))) {
+ if ((pe->flag & PEDGE_SEAM) || *r_pair ||
+ (topology_from_uvs && p_edge_implicit_seam(e, pe))) {
*r_pair = NULL;
return P_FALSE;
}
@@ -943,11 +944,14 @@ static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PBool impl, PEdge **r_pa
return (*r_pair != NULL);
}
-static PBool p_edge_connect_pair(PHandle *handle, PEdge *e, PBool impl, PEdge ***stack)
+static PBool p_edge_connect_pair(PHandle *handle,
+ PEdge *e,
+ PBool topology_from_uvs,
+ PEdge ***stack)
{
PEdge *pair = NULL;
- if (!e->pair && p_edge_has_pair(handle, e, impl, &pair)) {
+ if (!e->pair && p_edge_has_pair(handle, e, topology_from_uvs, &pair)) {
if (e->vert == pair->vert) {
p_face_flip(pair->face);
}
@@ -964,7 +968,7 @@ static PBool p_edge_connect_pair(PHandle *handle, PEdge *e, PBool impl, PEdge **
return (e->pair != NULL);
}
-static int p_connect_pairs(PHandle *handle, PBool impl)
+static int p_connect_pairs(PHandle *handle, PBool topology_from_uvs)
{
PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces),
"Pstackbase");
@@ -995,13 +999,13 @@ static int p_connect_pairs(PHandle *handle, PBool impl)
/* assign verts to charts so we can sort them later */
f->u.chart = ncharts;
- if (!p_edge_connect_pair(handle, e, impl, &stack)) {
+ if (!p_edge_connect_pair(handle, e, topology_from_uvs, &stack)) {
e->vert->edge = e;
}
- if (!p_edge_connect_pair(handle, e1, impl, &stack)) {
+ if (!p_edge_connect_pair(handle, e1, topology_from_uvs, &stack)) {
e1->vert->edge = e1;
}
- if (!p_edge_connect_pair(handle, e2, impl, &stack)) {
+ if (!p_edge_connect_pair(handle, e2, topology_from_uvs, &stack)) {
e2->vert->edge = e2;
}
}
@@ -4542,7 +4546,7 @@ void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
}
}
-void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl)
+void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool topology_from_uvs)
{
PHandle *phandle = (PHandle *)handle;
PChart *chart = phandle->construction_chart;
@@ -4551,7 +4555,7 @@ void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl)
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
- phandle->ncharts = p_connect_pairs(phandle, (PBool)impl);
+ phandle->ncharts = p_connect_pairs(phandle, (PBool)topology_from_uvs);
phandle->charts = p_split_charts(phandle, chart, phandle->ncharts);
p_chart_delete(phandle->construction_chart);
@@ -4568,7 +4572,7 @@ void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl)
p_chart_boundaries(chart, &nboundaries, &outer);
- if (!impl && nboundaries == 0) {
+ if (!topology_from_uvs && nboundaries == 0) {
p_chart_delete(chart);
continue;
}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h
index 833302d7da6..2427e589833 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.h
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.h
@@ -59,7 +59,7 @@ void param_face_add(ParamHandle *handle,
void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys);
-void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl);
+void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool topology_from_uvs);
void param_delete(ParamHandle *handle);
/* Least Squares Conformal Maps:
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 6989f0afbe8..108eca209b9 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -2174,6 +2174,7 @@ static int smart_project_exec(bContext *C, wmOperator *op)
.rotate_align_axis = 1,
.only_selected_faces = true,
.correct_aspect = true,
+ .use_seams = true,
});
uv_map_clip_correct_multi(objects_changed, object_changed_len, op);
diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc
index 188083b0f50..9c2b6c0e547 100644
--- a/source/blender/gpu/opengl/gl_debug_layer.cc
+++ b/source/blender/gpu/opengl/gl_debug_layer.cc
@@ -42,7 +42,7 @@ typedef void *GPUvoidptr;
#define void_ret
#define DEBUG_FUNC_DECLARE(pfn, rtn_type, fn, ...) \
- pfn real_##fn; \
+ static pfn real_##fn; \
static rtn_type GLAPIENTRY debug_##fn(ARG_LIST(__VA_ARGS__)) \
{ \
debug::check_gl_error("generated before " #fn); \
@@ -54,7 +54,7 @@ typedef void *GPUvoidptr;
namespace blender::gpu::debug {
/* List of wrapped functions. We dont have to support all of them.
- * Some functions might be declared as extern in GLEW. We cannot override them in this case.
+ * Some functions might be declared as `extern` in GLEW. We cannot override them in this case.
* Keep the list in alphabetical order. */
/* Avoid very long declarations. */
@@ -105,9 +105,11 @@ DEBUG_FUNC_DECLARE(PFNGLUSEPROGRAMPROC, void, glUseProgram, GLuint, program);
#undef DEBUG_FUNC_DECLARE
-/* Init a fallback layer (to KHR_debug) that covers only some functions.
- * We override the functions pointers by our own implementation that just checks glGetError.
- * Some additional functions (not overridable) are covered inside the header using wrappers. */
+/**
+ * Initialize a fallback layer (to KHR_debug) that covers only some functions.
+ * We override the functions pointers by our own implementation that just checks #glGetError.
+ * Some additional functions (not overridable) are covered inside the header using wrappers.
+ */
void init_debug_layer()
{
#define DEBUG_WRAP(function) \
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 2e029d041ec..de2d56bb264 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -27,6 +27,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
/* this system works on different transformation space levels;
@@ -280,3 +284,7 @@ typedef enum eBone_BBoneHandleType {
} eBone_BBoneHandleType;
#define MAXBONENAME 64
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_boid_types.h b/source/blender/makesdna/DNA_boid_types.h
index d5aa87fc8ae..7e010f27ce6 100644
--- a/source/blender/makesdna/DNA_boid_types.h
+++ b/source/blender/makesdna/DNA_boid_types.h
@@ -25,6 +25,10 @@
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum eBoidRuleType {
eBoidRuleType_None = 0,
/** go to goal assigned object or loudest assigned signal source */
@@ -222,3 +226,7 @@ typedef struct BoidSettings {
//#define BOID_RULE_LAND (1 << 3) /* goal */
//#define BOID_RULE_WITH_BOIDS (1 << 4) /* avoid collision */
//#define BOID_RULE_WITH_DEFLECTORS (1 << 5) /* avoid collision */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 3524cb7e7b5..756f21321f4 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -27,6 +27,10 @@
#include "DNA_curve_types.h"
#include "DNA_texture_types.h" /* for MTex */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct CurveMapping;
struct Image;
struct MTex;
@@ -980,3 +984,7 @@ enum {
#define MAX_BRUSH_PIXEL_RADIUS 500
#define GP_MAX_BRUSH_PIXEL_RADIUS 1000
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index 3d11b3cd7a3..11993d95c2c 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -25,6 +25,10 @@
#include "DNA_defs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* This struct contains all the global data required to run a simulation.
* At the time of this writing, this structure contains data appropriate
@@ -250,3 +254,7 @@ typedef enum {
CLOTH_COLLSETTINGS_FLAG_ENABLED = (1 << 1), /* enables cloth - object collisions */
CLOTH_COLLSETTINGS_FLAG_SELF = (1 << 2), /* enables selfcollisions */
} CLOTH_COLLISIONSETTINGS_FLAGS;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_collection_types.h b/source/blender/makesdna/DNA_collection_types.h
index e188426fdda..0a80e00d456 100644
--- a/source/blender/makesdna/DNA_collection_types.h
+++ b/source/blender/makesdna/DNA_collection_types.h
@@ -29,6 +29,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Collection;
struct Object;
@@ -109,3 +113,7 @@ typedef enum CollectionColorTag {
COLLECTION_COLOR_TOT,
} CollectionColorTag;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index ff419e1794e..bcebbf32ebd 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -26,6 +26,10 @@
#include "DNA_defs.h"
#include "DNA_vec_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* general defines for kernel functions */
#define CM_RESOL 32
#define CM_TABLE 256
@@ -214,3 +218,7 @@ typedef struct ColorManagedColorspaceSettings {
enum {
COLORMANAGE_VIEW_USE_CURVES = (1 << 0),
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 93a67602047..70d33d9ff94 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -28,6 +28,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Action;
struct Ipo;
struct Text;
@@ -1172,3 +1176,7 @@ typedef enum eStretchTo_Flags {
#define CONSTRAINT_RB_CONETWIST 4
#define CONSTRAINT_RB_VEHICLE 11
#define CONSTRAINT_RB_GENERIC6DOF 12
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 4eca81c27cc..372cfb225fa 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -28,6 +28,10 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define MAXTEXTBOX 256 /* used in readfile.c and editfont.c */
struct AnimData;
@@ -606,3 +610,7 @@ enum {
/* indicates point has been seen during surface duplication */
#define SURF_SEEN 4
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_curveprofile_types.h b/source/blender/makesdna/DNA_curveprofile_types.h
index 5b425741df2..450155a32e1 100644
--- a/source/blender/makesdna/DNA_curveprofile_types.h
+++ b/source/blender/makesdna/DNA_curveprofile_types.h
@@ -25,6 +25,10 @@
#include "DNA_vec_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/** Number of points in high resolution table is dynamic up to a maximum. */
#define PROF_TABLE_MAX 512
/** Number of table points per control point. */
@@ -98,3 +102,7 @@ typedef enum eCurveProfilePresets {
PROF_PRESET_CROWN = 3, /* Second molding example. */
PROF_PRESET_STEPS = 4, /* Dynamic number of steps defined by segments_len. */
} eCurveProfilePresets;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h
index 94f54a0d200..24dc90d6c21 100644
--- a/source/blender/makesdna/DNA_dynamicpaint_types.h
+++ b/source/blender/makesdna/DNA_dynamicpaint_types.h
@@ -21,6 +21,11 @@
#pragma once
#include "DNA_listBase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct PaintSurfaceData;
/* surface format */
@@ -261,3 +266,7 @@ typedef struct DynamicPaintBrushSettings {
float wave_factor, wave_clamp;
float max_velocity, smudge_strength;
} DynamicPaintBrushSettings;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h
index c25e9d0dded..33f2e1b47c0 100644
--- a/source/blender/makesdna/DNA_effect_types.h
+++ b/source/blender/makesdna/DNA_effect_types.h
@@ -23,6 +23,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* don't forget, new effects also in writefile.c for dna!!! */
#define PAF_MAXMULT 4
@@ -129,3 +133,7 @@ typedef struct WaveEff {
float timeoffs, lifetime;
} WaveEff;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index bb660fb8eaa..dc43524a325 100644
--- a/source/blender/makesdna/DNA_fileglobal_types.h
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -23,6 +23,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* FileGlobal stores a part of the current user-interface settings at
* the moment of saving, and the file-specific settings.
@@ -53,3 +57,7 @@ typedef struct FileGlobal {
/* example: if in 2.43 the meshes lose mesh data, minversion is 2.43 then too */
/* or: in 2.42, subversion 1, same as above, minversion then is 2.42, min subversion 1 */
/* (defines for version are in the BKE_blender_version.h file, for historic reasons) */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
index 2786d4df868..98007a2b0b1 100644
--- a/source/blender/makesdna/DNA_fluid_types.h
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -25,6 +25,10 @@
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* #FluidDomainSettings.flags
* Domain flags.
@@ -860,3 +864,7 @@ typedef struct FluidEffectorSettings {
short guide_mode;
char _pad2[2];
} FluidEffectorSettings;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index f84265eea1d..bd5afc457ac 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -23,6 +23,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct LatticeDeformData;
/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
@@ -801,3 +805,7 @@ typedef enum eTextureGpencil_Mode {
FILL = 1,
STROKE_AND_FILL = 2,
} eTextureGpencil_Mode;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 94b75642fd6..212f0bfa1c9 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -27,6 +27,10 @@
#include "DNA_brush_types.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct MDeformVert;
struct Curve;
@@ -835,3 +839,7 @@ typedef enum eGP_DrawMode {
#define GPENCIL_ANY_VERTEX_MASK(flag) \
((flag & (GP_VERTEX_MASK_SELECTMODE_POINT | GP_VERTEX_MASK_SELECTMODE_STROKE | \
GP_VERTEX_MASK_SELECTMODE_SEGMENT)))
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_gpu_types.h b/source/blender/makesdna/DNA_gpu_types.h
index b1ace1bda49..8cea1451525 100644
--- a/source/blender/makesdna/DNA_gpu_types.h
+++ b/source/blender/makesdna/DNA_gpu_types.h
@@ -23,6 +23,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Keep for 'Camera' versioning. */
/** Properties for dof effect. */
typedef struct GPUDOFSettings {
@@ -36,3 +40,7 @@ typedef struct GPUDOFSettings {
int num_blades;
int high_quality;
} GPUDOFSettings;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_hair_types.h b/source/blender/makesdna/DNA_hair_types.h
index 27799560395..2e819b32033 100644
--- a/source/blender/makesdna/DNA_hair_types.h
+++ b/source/blender/makesdna/DNA_hair_types.h
@@ -23,6 +23,10 @@
#include "DNA_ID.h"
#include "DNA_customdata_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct HairCurve {
/* Index of first point of hair curve. */
int firstpoint;
@@ -75,3 +79,7 @@ enum {
/* Only one material supported currently. */
#define HAIR_MATERIAL_NR 1
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 6e0e3d6d6b7..4edf06f90f7 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -27,6 +27,10 @@
#include "DNA_color_types.h" /* for color management */
#include "DNA_defs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct GPUTexture;
struct MovieCache;
struct PackedFile;
@@ -267,3 +271,7 @@ enum {
IMA_ALPHA_CHANNEL_PACKED = 2,
IMA_ALPHA_IGNORE = 3,
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h
index dfd06702b72..8bb94976414 100644
--- a/source/blender/makesdna/DNA_ipo_types.h
+++ b/source/blender/makesdna/DNA_ipo_types.h
@@ -36,6 +36,10 @@
#include "BLI_compiler_attrs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* -------------------------- Type Defines --------------------------- */
/* --- IPO Curve Driver --- */
@@ -516,3 +520,7 @@ typedef struct Ipo {
/* driver->flag */
/* invalid flag: currently only used for buggy pydriver expressions */
#define IPO_DRIVER_FLAG_INVALID (1 << 0)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
index 3a613d92e4f..9789d0d3520 100644
--- a/source/blender/makesdna/DNA_key_types.h
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -30,6 +30,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct Ipo;
@@ -158,3 +162,7 @@ enum {
#define KEYELEM_ELEM_LEN_BEZTRIPLE 4
#define KEYELEM_FLOAT_LEN_BEZTRIPLE (KEYELEM_ELEM_LEN_BEZTRIPLE * KEYELEM_ELEM_SIZE_CURVE)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_lattice_types.h b/source/blender/makesdna/DNA_lattice_types.h
index 797df3bd738..48eb8d90702 100644
--- a/source/blender/makesdna/DNA_lattice_types.h
+++ b/source/blender/makesdna/DNA_lattice_types.h
@@ -26,6 +26,10 @@
#include "DNA_ID.h"
#include "DNA_defs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct BPoint;
struct Ipo;
@@ -82,3 +86,7 @@ typedef struct Lattice {
#define LT_DS_EXPAND 4
#define LT_ACTBP_NONE -1
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h
index 1616cf949bd..9ca75347d23 100644
--- a/source/blender/makesdna/DNA_light_types.h
+++ b/source/blender/makesdna/DNA_light_types.h
@@ -26,6 +26,10 @@
#include "DNA_ID.h"
#include "DNA_defs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef MAX_MTEX
# define MAX_MTEX 18
#endif
@@ -154,3 +158,7 @@ typedef struct Light {
/* #define LA_AREA_BOX 3 */ /* UNUSED */
#define LA_AREA_DISK 4
#define LA_AREA_ELLIPSE 5
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_linestyle_types.h b/source/blender/makesdna/DNA_linestyle_types.h
index 422b99f00a0..b154de4507e 100644
--- a/source/blender/makesdna/DNA_linestyle_types.h
+++ b/source/blender/makesdna/DNA_linestyle_types.h
@@ -26,6 +26,10 @@
#include "DNA_ID.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef MAX_MTEX
# define MAX_MTEX 18
#endif
@@ -575,3 +579,7 @@ typedef struct FreestyleLineStyle {
ListBase thickness_modifiers;
ListBase geometry_modifiers;
} FreestyleLineStyle;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h
index f877b8f0c51..296f5bceb81 100644
--- a/source/blender/makesdna/DNA_mask_types.h
+++ b/source/blender/makesdna/DNA_mask_types.h
@@ -31,6 +31,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct Mask {
ID id;
struct AnimData *adt;
@@ -263,3 +267,7 @@ enum {
enum {
MASK_ANIMF_EXPAND = (1 << 4),
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 1d31b876068..919bd18be80 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -27,6 +27,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef MAX_MTEX
# define MAX_MTEX 18
#endif
@@ -359,3 +363,7 @@ enum {
GP_MATERIAL_FOLLOW_OBJ = 1,
GP_MATERIAL_FOLLOW_FIXED = 2,
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 7cc94a2ad0b..b2f8d845815 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -26,6 +26,10 @@
#include "DNA_customdata_types.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* -------------------------------------------------------------------- */
/** \name Geometry Elements
* \{ */
@@ -519,3 +523,7 @@ typedef struct MRecast {
} MRecast;
/** \} */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h
index de7427bc4dd..a827003a9a0 100644
--- a/source/blender/makesdna/DNA_meta_types.h
+++ b/source/blender/makesdna/DNA_meta_types.h
@@ -27,6 +27,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct BoundBox;
struct Ipo;
@@ -138,3 +142,7 @@ typedef struct MetaBall {
#define MB_NEGATIVE 2
#define MB_HIDE 8
#define MB_SCALE_RAD 16
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h
index 1cf93464f6a..7808dd68384 100644
--- a/source/blender/makesdna/DNA_nla_types.h
+++ b/source/blender/makesdna/DNA_nla_types.h
@@ -25,6 +25,10 @@
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Ipo;
struct Object;
struct bAction;
@@ -105,3 +109,7 @@ typedef enum eActStrip_Flag {
ACTSTRIP_REVERSE = (1 << 7),
ACTSTRIP_AUTO_BLENDS = (1 << 11),
} eActStrip_Flag;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 35fc1b81ecf..6de72fd996e 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -29,6 +29,10 @@
#include "DNA_texture_types.h"
#include "DNA_vec_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct ID;
struct Image;
@@ -1454,3 +1458,7 @@ typedef enum GeometryNodeTriangulateQuads {
GEO_NODE_TRIANGULATE_QUAD_ALTERNATE = 2,
GEO_NODE_TRIANGULATE_QUAD_SHORTEDGE = 3,
} GeometryNodeTriangulateQuads;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_object_enums.h b/source/blender/makesdna/DNA_object_enums.h
index c230cc3c872..ee30be934ca 100644
--- a/source/blender/makesdna/DNA_object_enums.h
+++ b/source/blender/makesdna/DNA_object_enums.h
@@ -22,6 +22,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/** #Object.mode */
typedef enum eObjectMode {
OB_MODE_OBJECT = 0,
@@ -71,3 +75,7 @@ typedef enum eDrawType {
(OB_MODE_EDIT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_SCULPT | OB_MODE_POSE | \
OB_MODE_PAINT_GPENCIL | OB_MODE_EDIT_GPENCIL | OB_MODE_SCULPT_GPENCIL | \
OB_MODE_WEIGHT_GPENCIL | OB_MODE_VERTEX_GPENCIL)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index 52d466fdbdd..cc376c0cebf 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -25,6 +25,10 @@
#include "DNA_defs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ID;
typedef struct TreeStoreElem {
@@ -128,3 +132,7 @@ enum {
TSE_KEYMAP_ITEM, \
TSE_ID_BASE, \
TSE_GP_LAYER))
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_packedFile_types.h b/source/blender/makesdna/DNA_packedFile_types.h
index b74368f767b..91c7de6bf3e 100644
--- a/source/blender/makesdna/DNA_packedFile_types.h
+++ b/source/blender/makesdna/DNA_packedFile_types.h
@@ -23,8 +23,16 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct PackedFile {
int size;
int seek;
void *data;
} PackedFile;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index bd19498eba7..d48144f90e8 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -27,6 +27,10 @@
#include "DNA_boid_types.h"
#include "DNA_defs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
typedef struct HairKey {
@@ -690,3 +694,7 @@ typedef enum eParticleTextureInfluence {
PAMAP_CHILD = (PAMAP_CLUMP | PAMAP_KINK_FREQ | PAMAP_KINK_AMP | PAMAP_ROUGH | PAMAP_LENGTH |
PAMAP_TWIST),
} eParticleTextureInfluence;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h
index 86cff098096..26f1db3324b 100644
--- a/source/blender/makesdna/DNA_pointcloud_types.h
+++ b/source/blender/makesdna/DNA_pointcloud_types.h
@@ -23,6 +23,10 @@
#include "DNA_ID.h"
#include "DNA_customdata_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct PointCloud {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id) */
@@ -57,3 +61,7 @@ enum {
/* Only one material supported currently. */
#define POINTCLOUD_MATERIAL_NR 1
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index cd11c18578a..48f183e1e28 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -27,6 +27,10 @@
#include "DNA_listBase.h"
#include "DNA_object_force_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Collection;
struct EffectorWeights;
@@ -368,3 +372,7 @@ typedef enum eRigidBodyCon_Flag {
} eRigidBodyCon_Flag;
/* ******************************** */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f65f8d32e97..85ec3dfdced 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -2275,6 +2275,8 @@ typedef enum eGPencil_Flags {
GP_TOOL_FLAG_THUMBNAIL_LIST = (1 << 3),
/* Generate wheight data for new strokes */
GP_TOOL_FLAG_CREATE_WEIGHTS = (1 << 4),
+ /* Automerge with last stroke */
+ GP_TOOL_FLAG_AUTOMERGE_STROKE = (1 << 5),
} eGPencil_Flags;
/* scene->r.simplify_gpencil */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index e42ff2a6e58..3a99a6f4ee8 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -30,6 +30,10 @@
#include "DNA_ID.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ARegion;
struct ARegionType;
struct PanelType;
@@ -723,3 +727,7 @@ enum {
/* Only editor overlays (currently gizmos only!) should be redrawn. */
RGN_DRAW_EDITOR_OVERLAYS = 32,
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h
index 4505eed3208..39ec8fcecb6 100644
--- a/source/blender/makesdna/DNA_sdna_types.h
+++ b/source/blender/makesdna/DNA_sdna_types.h
@@ -22,6 +22,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct MemArena;
#
@@ -118,3 +122,7 @@ typedef struct BHead8 {
uint64_t old;
int SDNAnr, nr;
} BHead8;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
index 07ccac5ba29..84b80310918 100644
--- a/source/blender/makesdna/DNA_shader_fx_types.h
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -23,6 +23,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct DRWShadingGroup;
/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
@@ -251,3 +255,7 @@ typedef struct WaveShaderFxData {
char _pad[4];
ShaderFxData_Runtime runtime;
} WaveShaderFxData;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
index 4ff694b29cc..a700c9fe2f8 100644
--- a/source/blender/makesdna/DNA_simulation_types.h
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -23,6 +23,10 @@
#include "DNA_ID.h"
#include "DNA_customdata_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct Simulation {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id) */
@@ -38,3 +42,7 @@ typedef struct Simulation {
enum {
SIM_DS_EXPAND = (1 << 0),
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index 39e1c730f10..b2bb50c56a2 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -25,6 +25,10 @@
#include "DNA_ID.h"
#include "DNA_defs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Ipo;
struct PackedFile;
@@ -116,3 +120,7 @@ enum {
SOUND_TAGS_WAVEFORM_NO_RELOAD = 1 << 0,
SOUND_TAGS_WAVEFORM_LOADING = (1 << 6),
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index a3aa79d29e8..3b805c6edec 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -36,6 +36,10 @@
/* Hum ... Not really nice... but needed for spacebuts. */
#include "DNA_view2d_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BLI_mempool;
struct FileLayout;
struct FileList;
@@ -1761,3 +1765,7 @@ typedef enum eSpace_Type {
#define IMG_SIZE_FALLBACK 256
/** \} */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_speaker_types.h b/source/blender/makesdna/DNA_speaker_types.h
index 82693689d68..29cccd1ef3a 100644
--- a/source/blender/makesdna/DNA_speaker_types.h
+++ b/source/blender/makesdna/DNA_speaker_types.h
@@ -22,6 +22,10 @@
#include "DNA_ID.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct bSound;
@@ -57,3 +61,7 @@ typedef struct Speaker {
#define SPK_DS_EXPAND (1 << 0)
#define SPK_MUTED (1 << 1)
// #define SPK_RELATIVE (1 << 2) /* UNUSED */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h
index 2dcb19d19b8..f63389bccf9 100644
--- a/source/blender/makesdna/DNA_text_types.h
+++ b/source/blender/makesdna/DNA_text_types.h
@@ -28,6 +28,10 @@
#include "DNA_ID.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct TextLine {
struct TextLine *next, *prev;
@@ -84,3 +88,7 @@ enum {
/** Use space instead of tabs. */
TXT_TABSTOSPACES = 1 << 10,
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 0bbeabf130f..5db523dfad1 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -28,6 +28,10 @@
#include "DNA_defs.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* match-moving data */
struct Image;
@@ -624,3 +628,7 @@ enum {
PLANE_TRACK_LOCKED = (1 << 2),
PLANE_TRACK_AUTOKEY = (1 << 3),
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_vec_types.h b/source/blender/makesdna/DNA_vec_types.h
index b8cbf85b683..0e3117c7f58 100644
--- a/source/blender/makesdna/DNA_vec_types.h
+++ b/source/blender/makesdna/DNA_vec_types.h
@@ -23,6 +23,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* types */
/** vector of two shorts. */
@@ -90,3 +94,7 @@ typedef struct DualQuat {
float scale[4][4];
float scale_weight;
} DualQuat;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h
index 4e2a6eba1f5..6f0820ff62c 100644
--- a/source/blender/makesdna/DNA_vfont_types.h
+++ b/source/blender/makesdna/DNA_vfont_types.h
@@ -28,6 +28,10 @@
#include "DNA_ID.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct PackedFile;
struct VFontData;
@@ -59,3 +63,7 @@ typedef struct VFont {
#define FO_CURS_IS_MOTION(mode) (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN))
#define FO_BUILTIN_NAME "<builtin>"
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index 085f463a1cc..131772d49b4 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -25,6 +25,10 @@
#include "DNA_vec_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ---------------------------------- */
/* View 2D data - stored per region */
@@ -173,3 +177,7 @@ enum {
V2D_ALIGN_NO_POS_Y = (1 << 2),
V2D_ALIGN_NO_NEG_Y = (1 << 3),
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_view3d_enums.h b/source/blender/makesdna/DNA_view3d_enums.h
index fdeebf20808..3de430e1177 100644
--- a/source/blender/makesdna/DNA_view3d_enums.h
+++ b/source/blender/makesdna/DNA_view3d_enums.h
@@ -20,6 +20,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/** Settings for offscreen rendering */
typedef enum eV3DOffscreenDrawFlag {
V3D_OFSDRAW_NONE = (0),
@@ -51,3 +55,7 @@ typedef enum eV3DShadingBackgroundType {
V3D_SHADING_BACKGROUND_WORLD = 1,
V3D_SHADING_BACKGROUND_VIEWPORT = 2,
} eV3DShadingBackgroundType;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 7e80fc1bd6d..9a233878840 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -39,6 +39,10 @@ struct wmTimer;
#include "DNA_object_types.h"
#include "DNA_view3d_enums.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct RegionView3D {
/** GL_PROJECTION matrix. */
@@ -635,3 +639,7 @@ enum {
/** #BKE_screen_view3d_zoom_to_fac() values above */
#define RV3D_CAMZOOM_MIN_FACTOR 0.1657359312880714853f
#define RV3D_CAMZOOM_MAX_FACTOR 44.9852813742385702928f
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index d6a3cdf04bf..1344f295ea9 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -22,6 +22,10 @@
#include "DNA_ID.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct PackedFile;
struct VolumeGridVector;
@@ -148,3 +152,7 @@ typedef enum SliceAxis {
/* Only one material supported currently. */
#define VOLUME_MATERIAL_NR 1
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 4b4e17b38bd..a7ad18d7cf3 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -31,6 +31,10 @@
#include "DNA_ID.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* defined here: */
struct wmWindow;
struct wmWindowManager;
@@ -569,3 +573,7 @@ enum {
* (the regiontype is maintained to prevent errors) */
OP_IS_MODAL_CURSOR_REGION = (1 << 3),
};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index b9ca2598ff3..edca887639e 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -24,6 +24,10 @@
#include "DNA_scene_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#
#
typedef struct bToolRef_Runtime {
@@ -188,3 +192,7 @@ typedef struct WorkSpaceInstanceHook {
typedef enum eWorkSpaceFlags {
WORKSPACE_USE_FILTER_BY_ORIGIN = (1 << 1),
} eWorkSpaceFlags;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
index b1ecf4abf85..d1132efc7a9 100644
--- a/source/blender/makesdna/DNA_world_types.h
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -26,6 +26,10 @@
#include "DNA_ID.h"
#include "DNA_defs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct Ipo;
struct bNodeTree;
@@ -110,3 +114,7 @@ enum {
* otherwise anim-editors will not read correctly
*/
#define WO_DS_SHOW_TEXS (1 << 2)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h
index caa5232788a..2ce32a723a7 100644
--- a/source/blender/makesdna/DNA_xr_types.h
+++ b/source/blender/makesdna/DNA_xr_types.h
@@ -22,6 +22,10 @@
#include "DNA_view3d_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct XrSessionSettings {
/** Shading settings, struct shared with 3D-View so settings are the same. */
struct View3DShading shading;
@@ -53,3 +57,7 @@ typedef enum eXRSessionBasePoseType {
XR_BASE_POSE_OBJECT = 1,
XR_BASE_POSE_CUSTOM = 2,
} eXRSessionBasePoseType;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h
index a5c9d2a79a0..f711056c575 100644
--- a/source/blender/makesdna/intern/dna_utils.h
+++ b/source/blender/makesdna/intern/dna_utils.h
@@ -20,6 +20,10 @@
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct GHash;
struct MemArena;
@@ -53,3 +57,7 @@ void DNA_alias_maps(enum eDNA_RenameDir version_dir,
const char *DNA_struct_rename_legacy_hack_alias_from_static(const char *name);
const char *DNA_struct_rename_legacy_hack_static_from_alias(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 8cc4f545ca9..03a61ccaa21 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -3458,6 +3458,13 @@ void RNA_def_property_collection_funcs(PropertyRNA *prop,
void RNA_def_property_srna(PropertyRNA *prop, const char *type)
{
+ char error[512];
+ if (rna_validate_identifier(type, error, false) == 0) {
+ CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", type, error);
+ DefRNA.error = true;
+ return;
+ }
+
prop->srna = (StructRNA *)type;
}
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index ee87ad19cbb..c4dcda71984 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -197,7 +197,6 @@ static char *rna_PointCache_path(PointerRNA *ptr)
}
default: {
return BLI_sprintfN("modifiers[\"%s\"].point_cache", name_esc);
- break;
}
}
}
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 03394a5faba..45406c3ddd3 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -2598,7 +2598,6 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain),
IDP_CopyPropertyContent(item_idprop_dst, item_idprop_src);
return RNA_property_collection_move(ptr_dst, prop_dst, item_index_added, item_index_dst);
- break;
}
default:
BLI_assert(0 && "Unsupported RNA override operation on collection");
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index c132c434468..235042122e6 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3273,6 +3273,16 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"if no vertex group selected, weight is not added");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "use_gpencil_automerge_strokes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_AUTOMERGE_STROKE);
+ RNA_def_property_boolean_default(prop, false);
+ RNA_def_property_ui_icon(prop, ICON_AUTOMERGE_OFF, 1);
+ RNA_def_property_ui_text(
+ prop,
+ "Automerge",
+ "Join by distance last drawn stroke with previous strokes in the active layer");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
RNA_def_property_struct_type(prop, "GPencilSculptSettings");
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 9b8386dd1b1..5419fc4ac7c 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -89,7 +89,9 @@ static Sequence *alloc_generic_sequence(
Strip *strip = seq->strip;
- if (file) {
+ /* Don't allocate StripElem for clip, mask and scene types. This struct is not handled in
+ * seq_dupli() function. */
+ if (file && !ELEM(type, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK, SEQ_TYPE_SCENE)) {
strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
BLI_split_dirfile(file, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 124ef950385..4152e8633e5 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -340,13 +340,16 @@ static void BMD_mesh_intersection(BMesh *bm,
* other than 0, -1, or 1 in the scaling part of the matrix.
*/
float cleaned_object_obmat[4][4];
+ float cleaned_operand_obmat[4][4];
clean_obmat(cleaned_object_obmat, object->obmat);
invert_m4_m4(imat, cleaned_object_obmat);
+ clean_obmat(cleaned_operand_obmat, operand_ob->obmat);
+ mul_m4_m4m4(omat, imat, cleaned_operand_obmat);
}
else {
invert_m4_m4(imat, object->obmat);
+ mul_m4_m4m4(omat, imat, operand_ob->obmat);
}
- mul_m4_m4m4(omat, imat, operand_ob->obmat);
BMVert *eve;
i = 0;
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index 36b9098d972..0b1ab85c059 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -188,6 +188,10 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
if (node->id == NULL) {
nodeRemoveAllSockets(ntree, node);
}
+ else if ((ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING))) {
+ /* Missing datablock, leave sockets unchanged so that when it comes back
+ * the links remain valid. */
+ }
else {
bNodeTree *ngroup = (bNodeTree *)node->id;
group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index eab9ab226e4..22c141e0958 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -109,6 +109,9 @@ PyDoc_STRVAR(bpy_bm_utils_vert_collapse_faces_doc,
" :type edge: :class:`bmesh.types.BMEdge`\n"
" :arg fac: The factor to use when merging customdata [0 - 1].\n"
" :type fac: float\n"
+ " :arg join_faces: When true the faces around the vertex will be joined otherwise "
+ "collapse the vertex by merging the 2 edges this vertex connects to into one.\n"
+ " :type join_faces: bool\n"
" :return: The resulting edge from the collapse operation.\n"
" :rtype: :class:`bmesh.types.BMEdge`\n");
static PyObject *bpy_bm_utils_vert_collapse_faces(PyObject *UNUSED(self), PyObject *args)
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 6e41bc96eed..a2125a5dff9 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1990,7 +1990,7 @@ static int pyrna_py_to_prop(
}
}
- /* Another exception, allow to pass a collection as an RNA property. */
+ /* Another exception, allow passing a collection as an RNA property. */
if (Py_TYPE(value) == &pyrna_prop_collection_Type) { /* Ok to ignore idprop collections. */
PointerRNA c_ptr;
BPy_PropertyRNA *value_prop = (BPy_PropertyRNA *)value;
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index b0e6b330968..8d2ab614728 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -95,7 +95,7 @@ static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
}
if (order_str) {
- order = euler_order_from_string(order_str, "Matrix.to_euler()");
+ order = euler_order_from_string(order_str, "Quaternion.to_euler()");
if (order == -1) {
return NULL;
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 77ced169dab..4b09c08f62c 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1311,11 +1311,11 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
return tri_list;
}
-static int boxPack_FromPyObject(PyObject *value, BoxPack **boxarray)
+static int boxPack_FromPyObject(PyObject *value, BoxPack **r_boxarray)
{
Py_ssize_t len, i;
PyObject *list_item, *item_1, *item_2;
- BoxPack *box;
+ BoxPack *boxarray;
/* Error checking must already be done */
if (!PyList_Check(value)) {
@@ -1325,17 +1325,17 @@ static int boxPack_FromPyObject(PyObject *value, BoxPack **boxarray)
len = PyList_GET_SIZE(value);
- *boxarray = MEM_mallocN(len * sizeof(BoxPack), "BoxPack box");
+ boxarray = MEM_mallocN(sizeof(BoxPack) * len, __func__);
for (i = 0; i < len; i++) {
list_item = PyList_GET_ITEM(value, i);
if (!PyList_Check(list_item) || PyList_GET_SIZE(list_item) < 4) {
- MEM_freeN(*boxarray);
+ MEM_freeN(boxarray);
PyErr_SetString(PyExc_TypeError, "can only pack a list of [x, y, w, h]");
return -1;
}
- box = (*boxarray) + i;
+ BoxPack *box = &boxarray[i];
item_1 = PyList_GET_ITEM(list_item, 2);
item_2 = PyList_GET_ITEM(list_item, 3);
@@ -1346,7 +1346,7 @@ static int boxPack_FromPyObject(PyObject *value, BoxPack **boxarray)
/* accounts for error case too and overwrites with own error */
if (box->w < 0.0f || box->h < 0.0f) {
- MEM_freeN(*boxarray);
+ MEM_freeN(boxarray);
PyErr_SetString(PyExc_TypeError,
"error parsing width and height values from list: "
"[x, y, w, h], not numbers or below zero");
@@ -1355,24 +1355,24 @@ static int boxPack_FromPyObject(PyObject *value, BoxPack **boxarray)
/* verts will be added later */
}
+
+ *r_boxarray = boxarray;
return 0;
}
-static void boxPack_ToPyObject(PyObject *value, BoxPack **boxarray)
+static void boxPack_ToPyObject(PyObject *value, const BoxPack *boxarray)
{
Py_ssize_t len, i;
PyObject *list_item;
- BoxPack *box;
len = PyList_GET_SIZE(value);
for (i = 0; i < len; i++) {
- box = (*boxarray) + i;
+ const BoxPack *box = &boxarray[i];
list_item = PyList_GET_ITEM(value, box->index);
PyList_SET_ITEM(list_item, 0, PyFloat_FromDouble(box->x));
PyList_SET_ITEM(list_item, 1, PyFloat_FromDouble(box->y));
}
- MEM_freeN(*boxarray);
}
PyDoc_STRVAR(M_Geometry_box_pack_2d_doc,
@@ -1407,7 +1407,8 @@ static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlis
/* Non Python function */
BLI_box_pack_2d(boxarray, len, &tot_width, &tot_height);
- boxPack_ToPyObject(boxlist, &boxarray);
+ boxPack_ToPyObject(boxlist, boxarray);
+ MEM_freeN(boxarray);
}
ret = PyTuple_New(2);
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index d9e2d32db0b..11e213d842d 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -60,6 +60,7 @@ enum {
/* RNA enums, just to be more readable */
enum {
+ SEQ_SIDE_MOUSE = -1,
SEQ_SIDE_NONE = 0,
SEQ_SIDE_LEFT,
SEQ_SIDE_RIGHT,
@@ -576,6 +577,25 @@ void BKE_sequencer_check_uuids_unique_and_report(const struct Scene *scene);
/* Generate new UUID for the given sequence. */
void BKE_sequence_session_uuid_generate(struct Sequence *sequence);
+/* **********************************************************************
+ * strip_edit.c
+ *
+ * Editing functions
+ * **********************************************************************
+ */
+
+typedef enum eSeqSplitMethod {
+ SEQ_SPLIT_SOFT,
+ SEQ_SPLIT_HARD,
+} eSeqSplitMethod;
+
+struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
+ struct Scene *scene,
+ struct ListBase *seqbase,
+ struct Sequence *seq,
+ const int timeline_frame,
+ const eSeqSplitMethod method);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 46a4ee0c03f..b03c5142a60 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -33,6 +33,7 @@
#include "BLT_translation.h"
+#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
@@ -194,3 +195,127 @@ void BKE_sequencer_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
}
}
}
+
+static void seq_split_set_left_hold_offset(Sequence *seq, int timeline_frame)
+{
+ /* Adjust within range of extended stillframes before strip. */
+ if (timeline_frame < seq->start) {
+ seq->start = timeline_frame - 1;
+ seq->anim_endofs += seq->len - 1;
+ seq->startstill = timeline_frame - seq->startdisp - 1;
+ seq->endstill = 0;
+ }
+ /* Adjust within range of strip contents. */
+ else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) {
+ seq->endofs = 0;
+ seq->endstill = 0;
+ seq->anim_endofs += (seq->start + seq->len) - timeline_frame;
+ }
+ /* Adjust within range of extended stillframes after strip. */
+ else if ((seq->start + seq->len) < timeline_frame) {
+ seq->endstill = timeline_frame - seq->start - seq->len;
+ }
+}
+
+static void seq_split_set_right_hold_offset(Sequence *seq, int timeline_frame)
+{
+ /* Adjust within range of extended stillframes before strip. */
+ if (timeline_frame < seq->start) {
+ seq->startstill = seq->start - timeline_frame;
+ }
+ /* Adjust within range of strip contents. */
+ else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) {
+ seq->anim_startofs += timeline_frame - seq->start;
+ seq->start = timeline_frame;
+ seq->startstill = 0;
+ seq->startofs = 0;
+ }
+ /* Adjust within range of extended stillframes after strip. */
+ else if ((seq->start + seq->len) < timeline_frame) {
+ seq->start = timeline_frame;
+ seq->startofs = 0;
+ seq->anim_startofs += seq->len - 1;
+ seq->endstill = seq->enddisp - timeline_frame - 1;
+ seq->startstill = 0;
+ }
+}
+
+static void seq_split_set_right_offset(Sequence *seq, int timeline_frame)
+{
+ /* Adjust within range of extended stillframes before strip. */
+ if (timeline_frame < seq->start) {
+ seq->start = timeline_frame - 1;
+ seq->startstill = timeline_frame - seq->startdisp - 1;
+ seq->endofs = seq->len - 1;
+ }
+ /* Adjust within range of extended stillframes after strip. */
+ else if ((seq->start + seq->len) < timeline_frame) {
+ seq->endstill -= seq->enddisp - timeline_frame;
+ }
+ BKE_sequence_tx_set_final_right(seq, timeline_frame);
+}
+
+static void seq_split_set_left_offset(Sequence *seq, int timeline_frame)
+{
+ /* Adjust within range of extended stillframes before strip. */
+ if (timeline_frame < seq->start) {
+ seq->startstill = seq->start - timeline_frame;
+ }
+ /* Adjust within range of extended stillframes after strip. */
+ if ((seq->start + seq->len) < timeline_frame) {
+ seq->start = timeline_frame - seq->len + 1;
+ seq->endstill = seq->enddisp - timeline_frame - 1;
+ }
+ BKE_sequence_tx_set_final_left(seq, timeline_frame);
+}
+
+/**
+ * Split Sequence at timeline_frame in two.
+ *
+ * \param bmain: Main in which Sequence is located
+ * \param scene: Scene in which Sequence is located
+ * \param seqbase: ListBase in which Sequence is located
+ * \param seq: Sequence to be split
+ * \param timeline_frame: frame at which seq is split.
+ * \param method: affects type of offset to be applied to resize Sequence
+ * \return poitner to created Sequence. This is always Sequence on right side.
+ */
+Sequence *SEQ_edit_strip_split(Main *bmain,
+ Scene *scene,
+ ListBase *seqbase,
+ Sequence *seq,
+ const int timeline_frame,
+ const eSeqSplitMethod method)
+{
+ if (timeline_frame <= seq->startdisp || timeline_frame >= seq->enddisp) {
+ return NULL;
+ }
+
+ if (method == SEQ_SPLIT_HARD) {
+ /* Precaution, needed because the length saved on-disk may not match the length saved in the
+ * blend file, or our code may have minor differences reading file length between versions.
+ * This causes hard-split to fail, see: T47862. */
+ BKE_sequence_reload_new_file(bmain, scene, seq, true);
+ BKE_sequence_calc(scene, seq);
+ }
+
+ Sequence *left_seq = seq;
+ Sequence *right_seq = BKE_sequence_dupli_recursive(
+ scene, scene, seqbase, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
+
+ switch (method) {
+ case SEQ_SPLIT_SOFT:
+ seq_split_set_left_offset(right_seq, timeline_frame);
+ seq_split_set_right_offset(left_seq, timeline_frame);
+ break;
+ case SEQ_SPLIT_HARD:
+ seq_split_set_right_hold_offset(left_seq, timeline_frame);
+ seq_split_set_left_hold_offset(right_seq, timeline_frame);
+ BKE_sequence_reload_new_file(bmain, scene, left_seq, false);
+ BKE_sequence_reload_new_file(bmain, scene, right_seq, false);
+ break;
+ }
+ BKE_sequence_calc(scene, left_seq);
+ BKE_sequence_calc(scene, right_seq);
+ return right_seq;
+}