diff options
author | Jacques Lucke <jacques@blender.org> | 2020-11-19 19:38:48 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2020-11-19 19:38:48 +0300 |
commit | bb960c85a55b823ee2c76911992043ac8c4eedda (patch) | |
tree | c3238b01838796fd128f122cae376fe5335f485c | |
parent | eb25446b9d2df9ca1cde808b12105be502adc4d1 (diff) | |
parent | 72a199e148b20c36a63cdf6c6af067c9bcdb3f92 (diff) |
Merge branch 'master' into geometry-nodes
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(®ion->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; +} |