WIP: UI: Status Bar Keymaps When Idle #121059
306
CMakeLists.txt
306
CMakeLists.txt
|
@ -120,14 +120,26 @@ enable_testing()
|
|||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
if("${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "11.0.0")
|
||||
message(FATAL_ERROR "\
|
||||
The minimum supported version of GCC is 11.0.0, found ${CMAKE_C_COMPILER_VERSION}"
|
||||
The minimum supported version of GCC is 11.0.0, found C compiler: ${CMAKE_C_COMPILER_VERSION}"
|
||||
)
|
||||
endif()
|
||||
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "11.0.0")
|
||||
message(FATAL_ERROR "\
|
||||
The minimum supported version of GCC is 11.0.0, found C++ compiler${CMAKE_CXX_COMPILER_VERSION}"
|
||||
)
|
||||
endif()
|
||||
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
if(CMAKE_COMPILER_IS_GNUCC AND ("${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "8.0"))
|
||||
message(FATAL_ERROR "\
|
||||
The minimum supported version of CLANG is 8.0, found ${CMAKE_C_COMPILER_VERSION}"
|
||||
)
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
if("${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "8.0")
|
||||
message(FATAL_ERROR "\
|
||||
The minimum supported version of CLANG is 8.0, found C compiler ${CMAKE_C_COMPILER_VERSION}"
|
||||
)
|
||||
endif()
|
||||
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "8.0")
|
||||
message(FATAL_ERROR "\
|
||||
The minimum supported version of CLANG is 8.0, found C++ compiler ${CMAKE_CXX_COMPILER_VERSION}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
if(MSVC_VERSION VERSION_LESS "1928")
|
||||
|
@ -2010,8 +2022,292 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|||
|
||||
CXX_WARN_ERROR_UNGUARDED_AVAILABILITY_NEW -Werror=unguarded-availability-new
|
||||
)
|
||||
if(MSVC_CLANG)
|
||||
# clang-cl produces an unhealthy ammount of warnings in its default
|
||||
# configuration as it for reasons unknown decided to enable all
|
||||
# warnings known to mankind. Resulting in a 5.5GB build log containing
|
||||
# well over 11 million warnings. The code below disables every single
|
||||
# one of them indiscriminately. Someone with time on their hands,
|
||||
# could/should go over these and either fix them or describe why we
|
||||
# would want to disable the warning. The list below contains both C
|
||||
# and C++ warnings for all warnings since clang has seemingly no
|
||||
# easy way to tell if something is a C or C++ specific warning and
|
||||
# manually auditing every single one of them just isn't in the cards
|
||||
# right now.
|
||||
|
||||
# /W3 is being removed, then added back again, this is because order
|
||||
# matters for clang and these flags are being placed before the
|
||||
# CMAKE_[LANGUAGE]_FLAGS which normally contain /W3, so we would
|
||||
# disable certain warings here only for them to be re-enabled by /W3
|
||||
# later on.
|
||||
remove_cc_flag("/W3")
|
||||
|
||||
add_check_c_compiler_flags(
|
||||
C_WARNINGS
|
||||
C_WARN_CLANG_CL_W3 /W3
|
||||
# The number behind each warn is the number of unique warning were
|
||||
# generated on 2024-04-24 (d2be9cecc28a03ff1f799e8c63f1f9f8eda7cce3)
|
||||
# especially the ones in the single and low double digits are likely
|
||||
# genuine problems that can be investigated.
|
||||
C_WARN_CLANG_CL_C++98_COMPAT -Wno-c++98-compat # 352692
|
||||
C_WARN_CLANG_CL_OLD_STYLE_CAST -Wno-old-style-cast # 178608
|
||||
C_WARN_CLANG_CL_UNSAFE_BUFFER_USAGE -Wno-unsafe-buffer-usage # 89032
|
||||
C_WARN_CLANG_CL_MISSING_PROTOTYPES -Wno-missing-prototypes # 25587
|
||||
C_WARN_CLANG_CL_SIGN_CONVERSION -Wno-sign-conversion # 20109
|
||||
C_WARN_CLANG_CL_MISSING_FIELD_INITIALIZERS -Wno-missing-field-initializers # 20060
|
||||
C_WARN_CLANG_CL_EXTRA_SEMI -Wno-extra-semi # 12513
|
||||
C_WARN_CLANG_CL_LANGUAGE_EXTENSION_TOKEN -Wno-language-extension-token # 11032
|
||||
C_WARN_CLANG_CL_IMPLICIT_FLOAT_CONVERSION -Wno-implicit-float-conversion # 11003
|
||||
C_WARN_CLANG_CL_C++98_COMPAT_PEDANTIC -Wno-c++98-compat-pedantic # 10336
|
||||
C_WARN_CLANG_CL_IMPLICIT_INT_FLOAT_CONVERSION -Wno-implicit-int-float-conversion # 7354
|
||||
C_WARN_CLANG_CL_DOUBLE_PROMOTION -Wno-double-promotion # 7350
|
||||
C_WARN_CLANG_CL_PRE_C++17_COMPAT -Wno-pre-c++17-compat # 7303
|
||||
C_WARN_CLANG_CL_SHORTEN_64_TO_32 -Wno-shorten-64-to-32 # 7085
|
||||
C_WARN_CLANG_CL_C++98_COMPAT_LOCAL_TYPE_TEMPLATE_ARGS -Wno-c++98-compat-local-type-template-args # 6906
|
||||
C_WARN_CLANG_CL_RESERVED_IDENTIFIER -Wno-reserved-identifier # 5886
|
||||
C_WARN_CLANG_CL_CAST_ALIGN -Wno-cast-align # 5513
|
||||
C_WARN_CLANG_CL_DOCUMENTATION -Wno-documentation # 5107
|
||||
C_WARN_CLANG_CL_DISABLED_MACRO_EXPANSION -Wno-disabled-macro-expansion # 4449
|
||||
C_WARN_CLANG_CL_EXTRA_SEMI_STMT -Wno-extra-semi-stmt # 4349
|
||||
C_WARN_CLANG_CL_ZERO_AS_NULL_POINTER_CONSTANT -Wno-zero-as-null-pointer-constant # 3209
|
||||
C_WARN_CLANG_CL_FLOAT_CONVERSION -Wno-float-conversion # 2869
|
||||
C_WARN_CLANG_CL_RESERVED_MACRO_IDENTIFIER -Wno-reserved-macro-identifier # 2862
|
||||
C_WARN_CLANG_CL_CAST_FUNCTION_TYPE_STRICT -Wno-cast-function-type-strict # 2663
|
||||
C_WARN_CLANG_CL_FLOAT_EQUAL -Wno-float-equal # 2153
|
||||
C_WARN_CLANG_CL_IMPLICIT_INT_CONVERSION -Wno-implicit-int-conversion # 2117
|
||||
C_WARN_CLANG_CL_SHADOW -Wno-shadow # 2068
|
||||
C_WARN_CLANG_CL_SHADOW_FIELD_IN_CONSTRUCTOR -Wno-shadow-field-in-constructor # 1829
|
||||
C_WARN_CLANG_CL_CAST_QUAL -Wno-cast-qual # 1742
|
||||
C_WARN_CLANG_CL_PRE_C++14_COMPAT -Wno-pre-c++14-compat # 1569
|
||||
C_WARN_CLANG_CL_GLOBAL_CONSTRUCTORS -Wno-global-constructors # 1402
|
||||
C_WARN_CLANG_CL_SWITCH_ENUM -Wno-switch-enum # 973
|
||||
C_WARN_CLANG_CL_EXIT_TIME_DESTRUCTORS -Wno-exit-time-destructors # 940
|
||||
C_WARN_CLANG_CL_CTAD_MAYBE_UNSUPPORTED -Wno-ctad-maybe-unsupported # 891
|
||||
C_WARN_CLANG_CL_UNDEFINED_FUNC_TEMPLATE -Wno-undefined-func-template # 863
|
||||
C_WARN_CLANG_CL_C++98_COMPAT_EXTRA_SEMI -Wno-c++98-compat-extra-semi # 848
|
||||
C_WARN_CLANG_CL_CAST_FUNCTION_TYPE -Wno-cast-function-type # 807
|
||||
C_WARN_CLANG_CL_NULLABILITY_EXTENSION -Wno-nullability-extension # 602
|
||||
C_WARN_CLANG_CL_SHADOW_FIELD -Wno-shadow-field # 585
|
||||
C_WARN_CLANG_CL_CONDITIONAL_UNINITIALIZED -Wno-conditional-uninitialized # 555
|
||||
C_WARN_CLANG_CL_UNUSED_PARAMETER -Wno-unused-parameter # 539
|
||||
C_WARN_CLANG_CL_SUGGEST_DESTRUCTOR_OVERRIDE -Wno-suggest-destructor-override # 356
|
||||
C_WARN_CLANG_CL_SHADOW_UNCAPTURED_LOCAL -Wno-shadow-uncaptured-local # 355
|
||||
C_WARN_CLANG_CL_UNUSED_MACROS -Wno-unused-macros # 289
|
||||
C_WARN_CLANG_CL_COVERED_SWITCH_DEFAULT -Wno-covered-switch-default # 233
|
||||
C_WARN_CLANG_CL_SIGNED_ENUM_BITFIELD -Wno-signed-enum-bitfield # 229
|
||||
C_WARN_CLANG_CL_DECLARATION_AFTER_STATEMENT -Wno-declaration-after-statement # 228
|
||||
C_WARN_CLANG_CL_IMPLICIT_FALLTHROUGH -Wno-implicit-fallthrough # 164
|
||||
C_WARN_CLANG_CL_NON_VIRTUAL_DTOR -Wno-non-virtual-dtor # 161
|
||||
C_WARN_CLANG_CL_NESTED_ANON_TYPES -Wno-nested-anon-types # 140
|
||||
C_WARN_CLANG_CL_GNU_ZERO_VARIADIC_MACRO_ARGUMENTS -Wno-gnu-zero-variadic-macro-arguments # 132
|
||||
C_WARN_CLANG_CL_UNREACHABLE_CODE_BREAK -Wno-unreachable-code-break # 115
|
||||
C_WARN_CLANG_CL_INCONSISTENT_MISSING_DESTRUCTOR_OVERRIDE -Wno-inconsistent-missing-destructor-override # 104
|
||||
C_WARN_CLANG_CL_FORMAT_PEDANTIC -Wno-format-pedantic # 97
|
||||
C_WARN_CLANG_CL_NONPORTABLE_SYSTEM_INCLUDE_PATH -Wno-nonportable-system-include-path # 95
|
||||
C_WARN_CLANG_CL_UNDEF -Wno-undef # 94
|
||||
C_WARN_CLANG_CL_IGNORED_QUALIFIERS -Wno-ignored-qualifiers # 93
|
||||
C_WARN_CLANG_CL_USED_BUT_MARKED_UNUSED -Wno-used-but-marked-unused # 83
|
||||
C_WARN_CLANG_CL_HEADER_HYGIENE -Wno-header-hygiene # 79
|
||||
C_WARN_CLANG_CL_CHAR_SUBSCRIPTS -Wno-char-subscripts # 76
|
||||
C_WARN_CLANG_CL_UNREACHABLE_CODE_RETURN -Wno-unreachable-code-return # 71
|
||||
C_WARN_CLANG_CL_UNUSED_TEMPLATE -Wno-unused-template # 66
|
||||
C_WARN_CLANG_CL_GNU_ANONYMOUS_STRUCT -Wno-gnu-anonymous-struct # 63
|
||||
C_WARN_CLANG_CL_DEPRECATED_COPY_WITH_USER_PROVIDED_DTOR -Wno-deprecated-copy-with-user-provided-dtor # 62
|
||||
C_WARN_CLANG_CL_INCONSISTENT_MISSING_OVERRIDE -Wno-inconsistent-missing-override # 54
|
||||
C_WARN_CLANG_CL_UNREACHABLE_CODE -Wno-unreachable-code # 52
|
||||
C_WARN_CLANG_CL_DEPRECATED_DYNAMIC_EXCEPTION_SPEC -Wno-deprecated-dynamic-exception-spec # 51
|
||||
C_WARN_CLANG_CL_BAD_FUNCTION_CAST -Wno-bad-function-cast # 50
|
||||
C_WARN_CLANG_CL_MICROSOFT_ENUM_VALUE -Wno-microsoft-enum-value # 47
|
||||
C_WARN_CLANG_CL_DEPRECATED_COPY_WITH_USER_PROVIDED_COPY -Wno-deprecated-copy-with-user-provided-copy # 41
|
||||
C_WARN_CLANG_CL_ZERO_LENGTH_ARRAY -Wno-zero-length-array # 39
|
||||
C_WARN_CLANG_CL_UNUSED_FUNCTION -Wno-unused-function # 38
|
||||
C_WARN_CLANG_CL_PEDANTIC -Wno-pedantic # 38
|
||||
C_WARN_CLANG_CL_DEPRECATED_COPY_WITH_DTOR -Wno-deprecated-copy-with-dtor # 37
|
||||
C_WARN_CLANG_CL_DOCUMENTATION_UNKNOWN_COMMAND -Wno-documentation-unknown-command # 34
|
||||
C_WARN_CLANG_CL_UNDEFINED_REINTERPRET_CAST -Wno-undefined-reinterpret-cast # 33
|
||||
C_WARN_CLANG_CL_FORMAT_NONLITERAL -Wno-format-nonliteral # 29
|
||||
C_WARN_CLANG_CL_COMMA -Wno-comma # 27
|
||||
C_WARN_CLANG_CL_DOCUMENTATION_DEPRECATED_SYNC -Wno-documentation-deprecated-sync # 26
|
||||
C_WARN_CLANG_CL_SHIFT_SIGN_OVERFLOW -Wno-shift-sign-overflow # 24
|
||||
C_WARN_CLANG_CL_PRE_C++17_COMPAT_PEDANTIC -Wno-pre-c++17-compat-pedantic # 24
|
||||
C_WARN_CLANG_CL_C++98_COMPAT_UNNAMED_TYPE_TEMPLATE_ARGS -Wno-c++98-compat-unnamed-type-template-args # 22
|
||||
C_WARN_CLANG_CL_SIGN_COMPARE -Wno-sign-compare # 21
|
||||
C_WARN_CLANG_CL_FORMAT -Wno-format # 21
|
||||
C_WARN_CLANG_CL_C++98_COMPAT_BIND_TO_TEMPORARY_COPY -Wno-c++98-compat-bind-to-temporary-copy # 21
|
||||
C_WARN_CLANG_CL_ENUM_ENUM_CONVERSION -Wno-enum-enum-conversion # 20
|
||||
C_WARN_CLANG_CL_ANON_ENUM_ENUM_CONVERSION -Wno-anon-enum-enum-conversion # 14
|
||||
C_WARN_CLANG_CL_RANGE_LOOP_BIND_REFERENCE -Wno-range-loop-bind-reference # 14
|
||||
C_WARN_CLANG_CL_ENUM_FLOAT_CONVERSION -Wno-enum-float-conversion # 12
|
||||
C_WARN_CLANG_CL_KEYWORD_MACRO -Wno-keyword-macro # 10
|
||||
C_WARN_CLANG_CL_DEPRECATED_COPY -Wno-deprecated-copy # 10
|
||||
C_WARN_CLANG_CL_UNUSED_MEMBER_FUNCTION -Wno-unused-member-function # 9
|
||||
C_WARN_CLANG_CL_MISSING_NORETURN -Wno-missing-noreturn # 8
|
||||
C_WARN_CLANG_CL_MISSING_VARIABLE_DECLARATIONS -Wno-missing-variable-declarations # 8
|
||||
C_WARN_CLANG_CL_DOCUMENTATION_HTML -Wno-documentation-html # 6
|
||||
C_WARN_CLANG_CL_GNU_REDECLARED_ENUM -Wno-gnu-redeclared-enum # 6
|
||||
C_WARN_CLANG_CL_DEPRECATED_DECLARATIONS -Wno-deprecated-declarations # 6
|
||||
C_WARN_CLANG_CL_OVERLOADED_VIRTUAL -Wno-overloaded-virtual # 5
|
||||
C_WARN_CLANG_CL_C++98_C++11_COMPAT_BINARY_LITERAL -Wno-c++98-c++11-compat-binary-literal # 4
|
||||
C_WARN_CLANG_CL_DEPRECATED_REDUNDANT_CONSTEXPR_STATIC_DEF -Wno-deprecated-redundant-constexpr-static-def # 4
|
||||
C_WARN_CLANG_CL_MISSING_BRACES -Wno-missing-braces # 4
|
||||
C_WARN_CLANG_CL_C99_EXTENSIONS -Wno-c99-extensions # 4
|
||||
C_WARN_CLANG_CL_STRICT_PROTOTYPES -Wno-strict-prototypes # 4
|
||||
C_WARN_CLANG_CL_UNREACHABLE_CODE_LOOP_INCREMENT -Wno-unreachable-code-loop-increment # 4
|
||||
C_WARN_CLANG_CL_GNU_CASE_RANGE -Wno-gnu-case-range # 4
|
||||
C_WARN_CLANG_CL_DUPLICATE_ENUM -Wno-duplicate-enum # 3
|
||||
C_WARN_CLANG_CL_NULL_POINTER_SUBTRACTION -Wno-null-pointer-subtraction # 2
|
||||
C_WARN_CLANG_CL_DEPRECATED_LITERAL_OPERATOR -Wno-deprecated-literal-operator # 2
|
||||
C_WARN_CLANG_CL_NEWLINE_EOF -Wno-newline-eof # 2
|
||||
C_WARN_CLANG_CL_MICROSOFT_CAST -Wno-microsoft-cast # 2
|
||||
C_WARN_CLANG_CL_DATE_TIME -Wno-date-time # 2
|
||||
C_WARN_CLANG_CL_DELETE_NON_ABSTRACT_NON_VIRTUAL_DTOR -Wno-delete-non-abstract-non-virtual-dtor # 2
|
||||
C_WARN_CLANG_CL_UNUSED_PRIVATE_FIELD -Wno-unused-private-field # 2
|
||||
C_WARN_CLANG_CL_FLEXIBLE_ARRAY_EXTENSIONS -Wno-flexible-array-extensions # 2
|
||||
C_WARN_CLANG_CL_STRING_CONVERSION -Wno-string-conversion # 2
|
||||
C_WARN_CLANG_CL_FINAL_DTOR_NON_FINAL_CLASS -Wno-final-dtor-non-final-class # 2
|
||||
C_WARN_CLANG_CL_MICROSOFT_UNQUALIFIED_FRIEND -Wno-microsoft-unqualified-friend # 2
|
||||
C_WARN_CLANG_CL_INVALID_NORETURN -Wno-invalid-noreturn # 1
|
||||
C_WARN_CLANG_CL_INVALID_UTF8 -Wno-invalid-utf8 # 1
|
||||
C_WARN_CLANG_CL_FOUR_CHAR_CONSTANTS -Wno-four-char-constants # 1
|
||||
C_WARN_CLANG_CL_PARENTHESES -Wno-parentheses # 1
|
||||
C_WARN_CLANG_CL_PESSIMIZING_MOVE -Wno-pessimizing-move # 1
|
||||
C_WARN_CLANG_CL_DEPRECATED_NON_PROTOTYPE -Wno-deprecated-non-prototype # 1
|
||||
C_WARN_CLANG_CL_BITFIELD_ENUM_CONVERSION -Wno-bitfield-enum-conversion # 1
|
||||
C_WARN_CLANG_CL_UNUSED_LAMBDA_CAPTURE -Wno-unused-lambda-capture # 1
|
||||
C_WARN_CLANG_CL_SHADOW_FIELD_IN_CONSTRUCTOR_MODIFIED -Wno-shadow-field-in-constructor-modified # 1
|
||||
)
|
||||
|
||||
add_check_cxx_compiler_flags(
|
||||
CXX_WARNINGS
|
||||
CXX_WARN_CLANG_CL_W3 /W3
|
||||
CXX_WARN_CLANG_CL_C++98_COMPAT -Wno-c++98-compat # 352692
|
||||
CXX_WARN_CLANG_CL_OLD_STYLE_CAST -Wno-old-style-cast # 178608
|
||||
CXX_WARN_CLANG_CL_UNSAFE_BUFFER_USAGE -Wno-unsafe-buffer-usage # 89032
|
||||
CXX_WARN_CLANG_CL_MISSING_PROTOTYPES -Wno-missing-prototypes # 25587
|
||||
CXX_WARN_CLANG_CL_SIGN_CONVERSION -Wno-sign-conversion # 20109
|
||||
CXX_WARN_CLANG_CL_MISSING_FIELD_INITIALIZERS -Wno-missing-field-initializers # 20060
|
||||
CXX_WARN_CLANG_CL_EXTRA_SEMI -Wno-extra-semi # 12513
|
||||
CXX_WARN_CLANG_CL_LANGUAGE_EXTENSION_TOKEN -Wno-language-extension-token # 11032
|
||||
CXX_WARN_CLANG_CL_IMPLICIT_FLOAT_CONVERSION -Wno-implicit-float-conversion # 11003
|
||||
CXX_WARN_CLANG_CL_C++98_COMPAT_PEDANTIC -Wno-c++98-compat-pedantic # 10336
|
||||
CXX_WARN_CLANG_CL_IMPLICIT_INT_FLOAT_CONVERSION -Wno-implicit-int-float-conversion # 7354
|
||||
CXX_WARN_CLANG_CL_DOUBLE_PROMOTION -Wno-double-promotion # 7350
|
||||
CXX_WARN_CLANG_CL_PRE_C++17_COMPAT -Wno-pre-c++17-compat # 7303
|
||||
CXX_WARN_CLANG_CL_SHORTEN_64_TO_32 -Wno-shorten-64-to-32 # 7085
|
||||
CXX_WARN_CLANG_CL_C++98_COMPAT_LOCAL_TYPE_TEMPLATE_ARGS -Wno-c++98-compat-local-type-template-args # 6906
|
||||
CXX_WARN_CLANG_CL_RESERVED_IDENTIFIER -Wno-reserved-identifier # 5886
|
||||
CXX_WARN_CLANG_CL_CAST_ALIGN -Wno-cast-align # 5513
|
||||
CXX_WARN_CLANG_CL_DOCUMENTATION -Wno-documentation # 5107
|
||||
CXX_WARN_CLANG_CL_DISABLED_MACRO_EXPANSION -Wno-disabled-macro-expansion # 4449
|
||||
CXX_WARN_CLANG_CL_EXTRA_SEMI_STMT -Wno-extra-semi-stmt # 4349
|
||||
CXX_WARN_CLANG_CL_ZERO_AS_NULL_POINTER_CONSTANT -Wno-zero-as-null-pointer-constant # 3209
|
||||
CXX_WARN_CLANG_CL_FLOAT_CONVERSION -Wno-float-conversion # 2869
|
||||
CXX_WARN_CLANG_CL_RESERVED_MACRO_IDENTIFIER -Wno-reserved-macro-identifier # 2862
|
||||
CXX_WARN_CLANG_CL_CAST_FUNCTION_TYPE_STRICT -Wno-cast-function-type-strict # 2663
|
||||
CXX_WARN_CLANG_CL_FLOAT_EQUAL -Wno-float-equal # 2153
|
||||
CXX_WARN_CLANG_CL_IMPLICIT_INT_CONVERSION -Wno-implicit-int-conversion # 2117
|
||||
CXX_WARN_CLANG_CL_SHADOW -Wno-shadow # 2068
|
||||
CXX_WARN_CLANG_CL_SHADOW_FIELD_IN_CONSTRUCTOR -Wno-shadow-field-in-constructor # 1829
|
||||
CXX_WARN_CLANG_CL_CAST_QUAL -Wno-cast-qual # 1742
|
||||
CXX_WARN_CLANG_CL_PRE_C++14_COMPAT -Wno-pre-c++14-compat # 1569
|
||||
CXX_WARN_CLANG_CL_GLOBAL_CONSTRUCTORS -Wno-global-constructors # 1402
|
||||
CXX_WARN_CLANG_CL_SWITCH_ENUM -Wno-switch-enum # 973
|
||||
CXX_WARN_CLANG_CL_EXIT_TIME_DESTRUCTORS -Wno-exit-time-destructors # 940
|
||||
CXX_WARN_CLANG_CL_CTAD_MAYBE_UNSUPPORTED -Wno-ctad-maybe-unsupported # 891
|
||||
CXX_WARN_CLANG_CL_UNDEFINED_FUNC_TEMPLATE -Wno-undefined-func-template # 863
|
||||
CXX_WARN_CLANG_CL_C++98_COMPAT_EXTRA_SEMI -Wno-c++98-compat-extra-semi # 848
|
||||
CXX_WARN_CLANG_CL_CAST_FUNCTION_TYPE -Wno-cast-function-type # 807
|
||||
CXX_WARN_CLANG_CL_NULLABILITY_EXTENSION -Wno-nullability-extension # 602
|
||||
CXX_WARN_CLANG_CL_SHADOW_FIELD -Wno-shadow-field # 585
|
||||
CXX_WARN_CLANG_CL_CONDITIONAL_UNINITIALIZED -Wno-conditional-uninitialized # 555
|
||||
CXX_WARN_CLANG_CL_UNUSED_PARAMETER -Wno-unused-parameter # 539
|
||||
CXX_WARN_CLANG_CL_SUGGEST_DESTRUCTOR_OVERRIDE -Wno-suggest-destructor-override # 356
|
||||
CXX_WARN_CLANG_CL_SHADOW_UNCAPTURED_LOCAL -Wno-shadow-uncaptured-local # 355
|
||||
CXX_WARN_CLANG_CL_UNUSED_MACROS -Wno-unused-macros # 289
|
||||
CXX_WARN_CLANG_CL_COVERED_SWITCH_DEFAULT -Wno-covered-switch-default # 233
|
||||
CXX_WARN_CLANG_CL_SIGNED_ENUM_BITFIELD -Wno-signed-enum-bitfield # 229
|
||||
CXX_WARN_CLANG_CL_DECLARATION_AFTER_STATEMENT -Wno-declaration-after-statement # 228
|
||||
CXX_WARN_CLANG_CL_IMPLICIT_FALLTHROUGH -Wno-implicit-fallthrough # 164
|
||||
CXX_WARN_CLANG_CL_NON_VIRTUAL_DTOR -Wno-non-virtual-dtor # 161
|
||||
CXX_WARN_CLANG_CL_NESTED_ANON_TYPES -Wno-nested-anon-types # 140
|
||||
CXX_WARN_CLANG_CL_GNU_ZERO_VARIADIC_MACRO_ARGUMENTS -Wno-gnu-zero-variadic-macro-arguments # 132
|
||||
CXX_WARN_CLANG_CL_UNREACHABLE_CODE_BREAK -Wno-unreachable-code-break # 115
|
||||
CXX_WARN_CLANG_CL_INCONSISTENT_MISSING_DESTRUCTOR_OVERRIDE -Wno-inconsistent-missing-destructor-override # 104
|
||||
CXX_WARN_CLANG_CL_FORMAT_PEDANTIC -Wno-format-pedantic # 97
|
||||
CXX_WARN_CLANG_CL_NONPORTABLE_SYSTEM_INCLUDE_PATH -Wno-nonportable-system-include-path # 95
|
||||
CXX_WARN_CLANG_CL_UNDEF -Wno-undef # 94
|
||||
CXX_WARN_CLANG_CL_IGNORED_QUALIFIERS -Wno-ignored-qualifiers # 93
|
||||
CXX_WARN_CLANG_CL_USED_BUT_MARKED_UNUSED -Wno-used-but-marked-unused # 83
|
||||
CXX_WARN_CLANG_CL_HEADER_HYGIENE -Wno-header-hygiene # 79
|
||||
CXX_WARN_CLANG_CL_CHAR_SUBSCRIPTS -Wno-char-subscripts # 76
|
||||
CXX_WARN_CLANG_CL_UNREACHABLE_CODE_RETURN -Wno-unreachable-code-return # 71
|
||||
CXX_WARN_CLANG_CL_UNUSED_TEMPLATE -Wno-unused-template # 66
|
||||
CXX_WARN_CLANG_CL_GNU_ANONYMOUS_STRUCT -Wno-gnu-anonymous-struct # 63
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_COPY_WITH_USER_PROVIDED_DTOR -Wno-deprecated-copy-with-user-provided-dtor # 62
|
||||
CXX_WARN_CLANG_CL_INCONSISTENT_MISSING_OVERRIDE -Wno-inconsistent-missing-override # 54
|
||||
CXX_WARN_CLANG_CL_UNREACHABLE_CODE -Wno-unreachable-code # 52
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_DYNAMIC_EXCEPTION_SPEC -Wno-deprecated-dynamic-exception-spec # 51
|
||||
CXX_WARN_CLANG_CL_BAD_FUNCTION_CAST -Wno-bad-function-cast # 50
|
||||
CXX_WARN_CLANG_CL_MICROSOFT_ENUM_VALUE -Wno-microsoft-enum-value # 47
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_COPY_WITH_USER_PROVIDED_COPY -Wno-deprecated-copy-with-user-provided-copy # 41
|
||||
CXX_WARN_CLANG_CL_ZERO_LENGTH_ARRAY -Wno-zero-length-array # 39
|
||||
CXX_WARN_CLANG_CL_UNUSED_FUNCTION -Wno-unused-function # 38
|
||||
CXX_WARN_CLANG_CL_PEDANTIC -Wno-pedantic # 38
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_COPY_WITH_DTOR -Wno-deprecated-copy-with-dtor # 37
|
||||
CXX_WARN_CLANG_CL_DOCUMENTATION_UNKNOWN_COMMAND -Wno-documentation-unknown-command # 34
|
||||
CXX_WARN_CLANG_CL_UNDEFINED_REINTERPRET_CAST -Wno-undefined-reinterpret-cast # 33
|
||||
CXX_WARN_CLANG_CL_FORMAT_NONLITERAL -Wno-format-nonliteral # 29
|
||||
CXX_WARN_CLANG_CL_COMMA -Wno-comma # 27
|
||||
CXX_WARN_CLANG_CL_DOCUMENTATION_DEPRECATED_SYNC -Wno-documentation-deprecated-sync # 26
|
||||
CXX_WARN_CLANG_CL_SHIFT_SIGN_OVERFLOW -Wno-shift-sign-overflow # 24
|
||||
CXX_WARN_CLANG_CL_PRE_C++17_COMPAT_PEDANTIC -Wno-pre-c++17-compat-pedantic # 24
|
||||
CXX_WARN_CLANG_CL_C++98_COMPAT_UNNAMED_TYPE_TEMPLATE_ARGS -Wno-c++98-compat-unnamed-type-template-args # 22
|
||||
CXX_WARN_CLANG_CL_SIGN_COMPARE -Wno-sign-compare # 21
|
||||
CXX_WARN_CLANG_CL_FORMAT -Wno-format # 21
|
||||
CXX_WARN_CLANG_CL_C++98_COMPAT_BIND_TO_TEMPORARY_COPY -Wno-c++98-compat-bind-to-temporary-copy # 21
|
||||
CXX_WARN_CLANG_CL_ENUM_ENUM_CONVERSION -Wno-enum-enum-conversion # 20
|
||||
CXX_WARN_CLANG_CL_ANON_ENUM_ENUM_CONVERSION -Wno-anon-enum-enum-conversion # 14
|
||||
CXX_WARN_CLANG_CL_RANGE_LOOP_BIND_REFERENCE -Wno-range-loop-bind-reference # 14
|
||||
CXX_WARN_CLANG_CL_ENUM_FLOAT_CONVERSION -Wno-enum-float-conversion # 12
|
||||
CXX_WARN_CLANG_CL_KEYWORD_MACRO -Wno-keyword-macro # 10
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_COPY -Wno-deprecated-copy # 10
|
||||
CXX_WARN_CLANG_CL_UNUSED_MEMBER_FUNCTION -Wno-unused-member-function # 9
|
||||
CXX_WARN_CLANG_CL_MISSING_NORETURN -Wno-missing-noreturn # 8
|
||||
CXX_WARN_CLANG_CL_MISSING_VARIABLE_DECLARATIONS -Wno-missing-variable-declarations # 8
|
||||
CXX_WARN_CLANG_CL_DOCUMENTATION_HTML -Wno-documentation-html # 6
|
||||
CXX_WARN_CLANG_CL_GNU_REDECLARED_ENUM -Wno-gnu-redeclared-enum # 6
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_DECLARATIONS -Wno-deprecated-declarations # 6
|
||||
CXX_WARN_CLANG_CL_OVERLOADED_VIRTUAL -Wno-overloaded-virtual # 5
|
||||
CXX_WARN_CLANG_CL_C++98_C++11_COMPAT_BINARY_LITERAL -Wno-c++98-c++11-compat-binary-literal # 4
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_REDUNDANT_CONSTEXPR_STATIC_DEF -Wno-deprecated-redundant-constexpr-static-def # 4
|
||||
CXX_WARN_CLANG_CL_MISSING_BRACES -Wno-missing-braces # 4
|
||||
CXX_WARN_CLANG_CL_C99_EXTENSIONS -Wno-c99-extensions # 4
|
||||
CXX_WARN_CLANG_CL_STRICT_PROTOTYPES -Wno-strict-prototypes # 4
|
||||
CXX_WARN_CLANG_CL_UNREACHABLE_CODE_LOOP_INCREMENT -Wno-unreachable-code-loop-increment # 4
|
||||
CXX_WARN_CLANG_CL_GNU_CASE_RANGE -Wno-gnu-case-range # 4
|
||||
CXX_WARN_CLANG_CL_DUPLICATE_ENUM -Wno-duplicate-enum # 3
|
||||
CXX_WARN_CLANG_CL_NULL_POINTER_SUBTRACTION -Wno-null-pointer-subtraction # 2
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_LITERAL_OPERATOR -Wno-deprecated-literal-operator # 2
|
||||
CXX_WARN_CLANG_CL_NEWLINE_EOF -Wno-newline-eof # 2
|
||||
CXX_WARN_CLANG_CL_MICROSOFT_CAST -Wno-microsoft-cast # 2
|
||||
CXX_WARN_CLANG_CL_DATE_TIME -Wno-date-time # 2
|
||||
CXX_WARN_CLANG_CL_DELETE_NON_ABSTRACT_NON_VIRTUAL_DTOR -Wno-delete-non-abstract-non-virtual-dtor # 2
|
||||
CXX_WARN_CLANG_CL_UNUSED_PRIVATE_FIELD -Wno-unused-private-field # 2
|
||||
CXX_WARN_CLANG_CL_FLEXIBLE_ARRAY_EXTENSIONS -Wno-flexible-array-extensions # 2
|
||||
CXX_WARN_CLANG_CL_STRING_CONVERSION -Wno-string-conversion # 2
|
||||
CXX_WARN_CLANG_CL_FINAL_DTOR_NON_FINAL_CLASS -Wno-final-dtor-non-final-class # 2
|
||||
CXX_WARN_CLANG_CL_MICROSOFT_UNQUALIFIED_FRIEND -Wno-microsoft-unqualified-friend # 2
|
||||
CXX_WARN_CLANG_CL_INVALID_NORETURN -Wno-invalid-noreturn # 1
|
||||
CXX_WARN_CLANG_CL_INVALID_UTF8 -Wno-invalid-utf8 # 1
|
||||
CXX_WARN_CLANG_CL_FOUR_CHAR_CONSTANTS -Wno-four-char-constants # 1
|
||||
CXX_WARN_CLANG_CL_PARENTHESES -Wno-parentheses # 1
|
||||
CXX_WARN_CLANG_CL_PESSIMIZING_MOVE -Wno-pessimizing-move # 1
|
||||
CXX_WARN_CLANG_CL_DEPRECATED_NON_PROTOTYPE -Wno-deprecated-non-prototype # 1
|
||||
CXX_WARN_CLANG_CL_BITFIELD_ENUM_CONVERSION -Wno-bitfield-enum-conversion # 1
|
||||
CXX_WARN_CLANG_CL_UNUSED_LAMBDA_CAPTURE -Wno-unused-lambda-capture # 1
|
||||
CXX_WARN_CLANG_CL_SHADOW_FIELD_IN_CONSTRUCTOR_MODIFIED -Wno-shadow-field-in-constructor-modified # 1
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# ---------------------
|
||||
|
|
|
@ -21,3 +21,20 @@ diff -Naur orig/src/cmake/compiler.cmake external_openimageio/src/cmake/compiler
|
|||
endif (MSVC)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"
|
||||
diff --git a/src/libOpenImageIO/imageioplugin.cpp b/src/libOpenImageIO/imageioplugin.cpp
|
||||
index 9ad45042e..d2a0210ff 100644
|
||||
--- a/src/libOpenImageIO/imageioplugin.cpp
|
||||
+++ b/src/libOpenImageIO/imageioplugin.cpp
|
||||
@@ -469,12 +469,6 @@ pvt::catalog_all_plugins(std::string searchpath)
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lock(imageio_mutex);
|
||||
append_if_env_exists(searchpath, "OIIO_LIBRARY_PATH", true);
|
||||
-#ifdef __APPLE__
|
||||
- append_if_env_exists(searchpath, "DYLD_LIBRARY_PATH");
|
||||
-#endif
|
||||
-#if defined(__linux__) || defined(__FreeBSD__)
|
||||
- append_if_env_exists(searchpath, "LD_LIBRARY_PATH");
|
||||
-#endif
|
||||
|
||||
size_t patlen = pattern.length();
|
||||
std::vector<std::string> dirs;
|
||||
|
|
|
@ -152,8 +152,6 @@ bool SimpleImage::initFromPpm(std::string filename)
|
|||
rowsize = windW * 3;
|
||||
}
|
||||
|
||||
unsigned char *pic = new unsigned char[size]; // (GLubyte *)malloc (size);
|
||||
|
||||
// Read in maximum value (ignore) , could be scanned with sscanf as well, but this should be
|
||||
// 255... 3rd line
|
||||
if (fgets(line, MAXLINE, fp) == nullptr) {
|
||||
|
@ -162,6 +160,8 @@ bool SimpleImage::initFromPpm(std::string filename)
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned char *pic = new unsigned char[size]; // (GLubyte *)malloc (size);
|
||||
|
||||
// Read in the pixel array row-by-row: 1st row = top scanline */
|
||||
unsigned char *ptr = nullptr;
|
||||
ptr = &pic[(windH - 1) * rowsize];
|
||||
|
|
|
@ -64,6 +64,13 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r
|
|||
void python_thread_state_save(void **python_thread_state);
|
||||
void python_thread_state_restore(void **python_thread_state);
|
||||
|
||||
static bool mesh_use_corner_normals(BL::Mesh &mesh, Mesh::SubdivisionType subdivision_type)
|
||||
{
|
||||
return mesh && (subdivision_type == Mesh::SUBDIVISION_NONE) &&
|
||||
(static_cast<const ::Mesh *>(mesh.ptr.data)->normals_domain(true) ==
|
||||
blender::bke::MeshNormalDomain::Corner);
|
||||
}
|
||||
|
||||
static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Depsgraph & /*depsgraph*/,
|
||||
|
@ -88,27 +95,33 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
|||
|
||||
BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) :
|
||||
BL::Mesh(PointerRNA_NULL);
|
||||
const bool split_faces = (mesh) && (subdivision_type == Mesh::SUBDIVISION_NONE) &&
|
||||
(static_cast<const ::Mesh *>(mesh.ptr.data)->normals_domain(true) ==
|
||||
blender::bke::MeshNormalDomain::Corner);
|
||||
|
||||
bool use_corner_normals = false;
|
||||
|
||||
if (b_ob_info.is_real_object_data()) {
|
||||
if (mesh) {
|
||||
/* Make a copy to split faces if we use auto-smooth, otherwise not needed.
|
||||
* Also in edit mode do we need to make a copy, to ensure data layers like
|
||||
* UV are not empty. */
|
||||
if (mesh.is_editmode() || split_faces) {
|
||||
if (mesh.is_editmode()) {
|
||||
/* Flush editmesh to mesh, including all data layers. */
|
||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||
use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type);
|
||||
}
|
||||
else if (mesh_use_corner_normals(mesh, subdivision_type)) {
|
||||
/* Make a copy to split faces. */
|
||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||
use_corner_normals = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||
use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* TODO: what to do about non-mesh geometry instances? */
|
||||
use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -121,7 +134,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
|||
#endif
|
||||
|
||||
if (mesh) {
|
||||
if (split_faces) {
|
||||
if (use_corner_normals) {
|
||||
mesh.split_faces();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,14 @@ shader node_glass_bsdf(color Color = 0.8,
|
|||
normal Normal = N,
|
||||
output closure color BSDF = 0)
|
||||
{
|
||||
float r2 = Roughness * Roughness;
|
||||
color base_color = max(Color, color(0.0));
|
||||
float r2 = clamp(Roughness, 0.0, 1.0);
|
||||
r2 = r2 * r2;
|
||||
float eta = max(IOR, 1e-5);
|
||||
eta = backfacing() ? 1.0 / eta : eta;
|
||||
color F0 = F0_from_ior(eta);
|
||||
color F90 = color(1.0);
|
||||
|
||||
BSDF = generalized_schlick_bsdf(
|
||||
Normal, vector(0.0), Color, Color, r2, r2, F0, F90, -eta, distribution);
|
||||
Normal, vector(0.0), base_color, base_color, r2, r2, F0, F90, -eta, distribution);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@ shader node_glossy_bsdf(color Color = 0.8,
|
|||
output closure color BSDF = 0)
|
||||
{
|
||||
/* compute roughness */
|
||||
float roughness = Roughness * Roughness;
|
||||
color base_color = max(Color, color(0.0));
|
||||
float roughness = clamp(Roughness, 0.0, 1.0);
|
||||
roughness = roughness * roughness;
|
||||
float roughness_u, roughness_v;
|
||||
float aniso = clamp(Anisotropy, -0.99, 0.99);
|
||||
|
||||
|
@ -41,7 +43,8 @@ shader node_glossy_bsdf(color Color = 0.8,
|
|||
}
|
||||
|
||||
if (distribution == "Multiscatter GGX")
|
||||
BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, roughness_u, roughness_v, Color);
|
||||
BSDF = base_color *
|
||||
microfacet_multi_ggx_aniso(Normal, T, roughness_u, roughness_v, base_color);
|
||||
else
|
||||
BSDF = Color * microfacet(distribution, Normal, T, roughness_u, roughness_v, 0.0, 0);
|
||||
BSDF = base_color * microfacet(distribution, Normal, T, roughness_u, roughness_v, 0.0, 0);
|
||||
}
|
||||
|
|
|
@ -11,10 +11,11 @@ shader node_sheen_bsdf(color Color = 0.8,
|
|||
normal Normal = N,
|
||||
output closure color BSDF = 0)
|
||||
{
|
||||
color base_color = max(Color, color(0.0));
|
||||
float roughness = clamp(Roughness, 0.0, 1.0);
|
||||
|
||||
if (distribution == "ashikhmin")
|
||||
BSDF = Color * ashikhmin_velvet(Normal, roughness);
|
||||
BSDF = base_color * ashikhmin_velvet(Normal, roughness);
|
||||
else if (distribution == "microfiber")
|
||||
BSDF = Color * sheen(Normal, roughness);
|
||||
BSDF = base_color * sheen(Normal, roughness);
|
||||
}
|
||||
|
|
|
@ -13,14 +13,15 @@ shader node_subsurface_scattering(color Color = 0.8,
|
|||
normal Normal = N,
|
||||
output closure color BSSRDF = 0)
|
||||
{
|
||||
BSSRDF = Color * bssrdf(method,
|
||||
Normal,
|
||||
Scale * Radius,
|
||||
Color,
|
||||
"ior",
|
||||
IOR,
|
||||
"anisotropy",
|
||||
Anisotropy,
|
||||
"roughness",
|
||||
1.0);
|
||||
color base_color = max(Color, color(0.0));
|
||||
BSSRDF = base_color * bssrdf(method,
|
||||
Normal,
|
||||
Scale * Radius,
|
||||
base_color,
|
||||
"ior",
|
||||
IOR,
|
||||
"anisotropy",
|
||||
Anisotropy,
|
||||
"roughness",
|
||||
1.0);
|
||||
}
|
||||
|
|
|
@ -470,24 +470,24 @@ ccl_device
|
|||
break;
|
||||
}
|
||||
|
||||
float roughness = sqr(param1);
|
||||
float roughness = sqr(saturatef(param1));
|
||||
|
||||
bsdf->N = maybe_ensure_valid_specular_reflection(sd, N);
|
||||
bsdf->ior = 1.0f;
|
||||
|
||||
/* compute roughness */
|
||||
float anisotropy = clamp(param2, -0.99f, 0.99f);
|
||||
if (data_node.y == SVM_STACK_INVALID || fabsf(anisotropy) <= 1e-4f) {
|
||||
if (data_node.w == SVM_STACK_INVALID || fabsf(anisotropy) <= 1e-4f) {
|
||||
/* Isotropic case. */
|
||||
bsdf->T = zero_float3();
|
||||
bsdf->alpha_x = roughness;
|
||||
bsdf->alpha_y = roughness;
|
||||
}
|
||||
else {
|
||||
bsdf->T = stack_load_float3(stack, data_node.y);
|
||||
bsdf->T = stack_load_float3(stack, data_node.w);
|
||||
|
||||
/* rotate tangent */
|
||||
float rotation = stack_load_float(stack, data_node.z);
|
||||
float rotation = stack_load_float(stack, data_node.y);
|
||||
if (rotation != 0.0f) {
|
||||
bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F);
|
||||
}
|
||||
|
@ -512,8 +512,9 @@ ccl_device
|
|||
else {
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
|
||||
kernel_assert(stack_valid(data_node.w));
|
||||
const Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.w));
|
||||
kernel_assert(stack_valid(data_node.z));
|
||||
const Spectrum color = max(rgb_to_spectrum(stack_load_float3(stack, data_node.z)),
|
||||
zero_spectrum());
|
||||
bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, color);
|
||||
}
|
||||
}
|
||||
|
@ -580,12 +581,12 @@ ccl_device
|
|||
|
||||
float ior = fmaxf(param2, 1e-5f);
|
||||
bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / ior : ior;
|
||||
bsdf->alpha_x = bsdf->alpha_y = sqr(param1);
|
||||
bsdf->alpha_x = bsdf->alpha_y = sqr(saturatef(param1));
|
||||
|
||||
fresnel->f0 = make_float3(F0_from_ior(ior));
|
||||
fresnel->f90 = one_spectrum();
|
||||
fresnel->exponent = -ior;
|
||||
const float3 color = stack_load_float3(stack, data_node.z);
|
||||
const float3 color = max(stack_load_float3(stack, data_node.y), zero_float3());
|
||||
fresnel->reflection_tint = reflective_caustics ? rgb_to_spectrum(color) : zero_spectrum();
|
||||
fresnel->transmission_tint = refractive_caustics ? rgb_to_spectrum(color) :
|
||||
zero_spectrum();
|
||||
|
@ -622,7 +623,7 @@ ccl_device
|
|||
|
||||
if (bsdf) {
|
||||
bsdf->N = N;
|
||||
bsdf->roughness = param1;
|
||||
bsdf->roughness = saturatef(param1);
|
||||
|
||||
sd->flag |= bsdf_sheen_setup(kg, sd, bsdf);
|
||||
}
|
||||
|
@ -834,10 +835,10 @@ ccl_device
|
|||
bsdf->N = maybe_ensure_valid_specular_reflection(sd, N);
|
||||
bsdf->roughness1 = param1;
|
||||
bsdf->roughness2 = param2;
|
||||
bsdf->offset = -stack_load_float(stack, data_node.z);
|
||||
bsdf->offset = -stack_load_float(stack, data_node.y);
|
||||
|
||||
if (stack_valid(data_node.y)) {
|
||||
bsdf->T = normalize(stack_load_float3(stack, data_node.y));
|
||||
if (stack_valid(data_node.w)) {
|
||||
bsdf->T = normalize(stack_load_float3(stack, data_node.w));
|
||||
}
|
||||
else if (!(sd->type & PRIMITIVE_CURVE)) {
|
||||
bsdf->T = normalize(sd->dPdv);
|
||||
|
@ -866,12 +867,13 @@ ccl_device
|
|||
ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, weight);
|
||||
|
||||
if (bssrdf) {
|
||||
bssrdf->radius = rgb_to_spectrum(stack_load_float3(stack, data_node.z) * param1);
|
||||
bssrdf->radius = max(rgb_to_spectrum(stack_load_float3(stack, data_node.y) * param1),
|
||||
zero_spectrum());
|
||||
bssrdf->albedo = closure_weight;
|
||||
bssrdf->N = maybe_ensure_valid_specular_reflection(sd, N);
|
||||
bssrdf->ior = param2;
|
||||
bssrdf->alpha = 1.0f;
|
||||
bssrdf->anisotropy = stack_load_float(stack, data_node.w);
|
||||
bssrdf->anisotropy = stack_load_float(stack, data_node.z);
|
||||
|
||||
sd->flag |= bssrdf_setup(sd, bssrdf, path_flag, (ClosureType)type);
|
||||
}
|
||||
|
|
|
@ -2283,14 +2283,14 @@ bool BsdfBaseNode::has_bump()
|
|||
BsdfNode::BsdfNode(const NodeType *node_type) : BsdfBaseNode(node_type) {}
|
||||
|
||||
void BsdfNode::compile(SVMCompiler &compiler,
|
||||
ShaderInput *param1,
|
||||
ShaderInput *param2,
|
||||
ShaderInput *param3,
|
||||
ShaderInput *param4)
|
||||
ShaderInput *bsdf_y,
|
||||
ShaderInput *bsdf_z,
|
||||
ShaderInput *data_y,
|
||||
ShaderInput *data_z,
|
||||
ShaderInput *data_w)
|
||||
{
|
||||
ShaderInput *color_in = input("Color");
|
||||
ShaderInput *normal_in = input("Normal");
|
||||
ShaderInput *tangent_in = input("Tangent");
|
||||
|
||||
if (color_in->link) {
|
||||
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
|
||||
|
@ -2300,21 +2300,20 @@ void BsdfNode::compile(SVMCompiler &compiler,
|
|||
}
|
||||
|
||||
int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
|
||||
int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) :
|
||||
SVM_STACK_INVALID;
|
||||
int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
|
||||
int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
|
||||
int data_y_offset = (data_y) ? compiler.stack_assign(data_y) : SVM_STACK_INVALID;
|
||||
int data_z_offset = (data_z) ? compiler.stack_assign(data_z) : SVM_STACK_INVALID;
|
||||
int data_w_offset = (data_w) ? compiler.stack_assign(data_w) : SVM_STACK_INVALID;
|
||||
|
||||
compiler.add_node(
|
||||
NODE_CLOSURE_BSDF,
|
||||
compiler.encode_uchar4(closure,
|
||||
(param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
|
||||
(param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
|
||||
(bsdf_y) ? compiler.stack_assign(bsdf_y) : SVM_STACK_INVALID,
|
||||
(bsdf_z) ? compiler.stack_assign(bsdf_z) : SVM_STACK_INVALID,
|
||||
compiler.closure_mix_weight_offset()),
|
||||
__float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
|
||||
__float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
|
||||
__float_as_int((bsdf_y) ? get_float(bsdf_y->socket_type) : 0.0f),
|
||||
__float_as_int((bsdf_z) ? get_float(bsdf_z->socket_type) : 0.0f));
|
||||
|
||||
compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
|
||||
compiler.add_node(normal_offset, data_y_offset, data_z_offset, data_w_offset);
|
||||
}
|
||||
|
||||
void BsdfNode::compile(SVMCompiler &compiler)
|
||||
|
@ -2392,13 +2391,21 @@ void GlossyBsdfNode::compile(SVMCompiler &compiler)
|
|||
{
|
||||
closure = distribution;
|
||||
|
||||
ShaderInput *tangent = input("Tangent");
|
||||
tangent = compiler.is_linked(tangent) ? tangent : nullptr;
|
||||
|
||||
/* TODO: Just use weight for legacy MultiGGX? Would also simplify OSL. */
|
||||
if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
|
||||
BsdfNode::compile(
|
||||
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
|
||||
BsdfNode::compile(compiler,
|
||||
input("Roughness"),
|
||||
input("Anisotropy"),
|
||||
input("Rotation"),
|
||||
input("Color"),
|
||||
tangent);
|
||||
}
|
||||
else {
|
||||
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
|
||||
BsdfNode::compile(
|
||||
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), nullptr, tangent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3535,7 +3542,11 @@ void HairBsdfNode::compile(SVMCompiler &compiler)
|
|||
{
|
||||
closure = component;
|
||||
|
||||
BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
|
||||
ShaderInput *tangent = input("Tangent");
|
||||
tangent = compiler.is_linked(tangent) ? tangent : nullptr;
|
||||
|
||||
BsdfNode::compile(
|
||||
compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"), nullptr, tangent);
|
||||
}
|
||||
|
||||
void HairBsdfNode::compile(OSLCompiler &compiler)
|
||||
|
|
|
@ -479,10 +479,11 @@ class BsdfNode : public BsdfBaseNode {
|
|||
SHADER_NODE_BASE_CLASS(BsdfNode)
|
||||
|
||||
void compile(SVMCompiler &compiler,
|
||||
ShaderInput *param1,
|
||||
ShaderInput *param2,
|
||||
ShaderInput *param3 = NULL,
|
||||
ShaderInput *param4 = NULL);
|
||||
ShaderInput *bsdf_y,
|
||||
ShaderInput *bsdf_z,
|
||||
ShaderInput *data_y = nullptr,
|
||||
ShaderInput *data_z = nullptr,
|
||||
ShaderInput *data_w = nullptr);
|
||||
|
||||
NODE_SOCKET_API(float3, color)
|
||||
NODE_SOCKET_API(float3, normal)
|
||||
|
|
|
@ -294,9 +294,14 @@ int SVMCompiler::stack_assign(ShaderOutput *output)
|
|||
return output->stack_offset;
|
||||
}
|
||||
|
||||
bool SVMCompiler::is_linked(ShaderInput *input)
|
||||
{
|
||||
return (input->link || input->constant_folded_in);
|
||||
}
|
||||
|
||||
int SVMCompiler::stack_assign_if_linked(ShaderInput *input)
|
||||
{
|
||||
if (input->link || input->constant_folded_in) {
|
||||
if (is_linked(input)) {
|
||||
return stack_assign(input);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ class SVMCompiler {
|
|||
|
||||
int stack_assign(ShaderOutput *output);
|
||||
int stack_assign(ShaderInput *input);
|
||||
bool is_linked(ShaderInput *input);
|
||||
int stack_assign_if_linked(ShaderInput *input);
|
||||
int stack_assign_if_linked(ShaderOutput *output);
|
||||
int stack_find_offset(int size);
|
||||
|
|
|
@ -123,6 +123,10 @@ typedef enum {
|
|||
* Supports IME text input methods (when `WITH_INPUT_IME` is defined).
|
||||
*/
|
||||
GHOST_kCapabilityInputIME = (1 << 6),
|
||||
/**
|
||||
* Support detecting the physical trackpad direction.
|
||||
*/
|
||||
GHOST_kCapabilityTrackpadPhysicalDirection = (1 << 7),
|
||||
} GHOST_TCapabilityFlag;
|
||||
|
||||
/**
|
||||
|
@ -132,7 +136,8 @@ typedef enum {
|
|||
#define GHOST_CAPABILITY_FLAG_ALL \
|
||||
(GHOST_kCapabilityCursorWarp | GHOST_kCapabilityWindowPosition | \
|
||||
GHOST_kCapabilityPrimaryClipboard | GHOST_kCapabilityGPUReadFrontBuffer | \
|
||||
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample | GHOST_kCapabilityInputIME)
|
||||
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample | \
|
||||
GHOST_kCapabilityInputIME | GHOST_kCapabilityTrackpadPhysicalDirection)
|
||||
|
||||
/* Xtilt and Ytilt represent how much the pen is tilted away from
|
||||
* vertically upright in either the X or Y direction, with X and Y the
|
||||
|
|
|
@ -108,6 +108,8 @@ static bool has_libdecor = true;
|
|||
# endif
|
||||
#endif
|
||||
|
||||
static signed char has_wl_trackpad_physical_direction = -1;
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
|
||||
|
@ -6410,6 +6412,8 @@ static void gwl_registry_wl_seat_add(GWL_Display *display, const GWL_RegisteryAd
|
|||
display->seats.push_back(seat);
|
||||
wl_seat_add_listener(seat->wl.seat, &seat_listener, seat);
|
||||
gwl_registry_entry_add(display, params, static_cast<void *>(seat));
|
||||
|
||||
has_wl_trackpad_physical_direction = version >= 9;
|
||||
}
|
||||
static void gwl_registry_wl_seat_update(GWL_Display *display,
|
||||
const GWL_RegisteryUpdate_Params ¶ms)
|
||||
|
@ -8367,6 +8371,9 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_visibility_set(const bool visible)
|
|||
|
||||
GHOST_TCapabilityFlag GHOST_SystemWayland::getCapabilities() const
|
||||
{
|
||||
GHOST_ASSERT(has_wl_trackpad_physical_direction != -1,
|
||||
"The trackpad direction was expected to be initialized");
|
||||
|
||||
return GHOST_TCapabilityFlag(
|
||||
GHOST_CAPABILITY_FLAG_ALL &
|
||||
~(
|
||||
|
@ -8388,7 +8395,9 @@ GHOST_TCapabilityFlag GHOST_SystemWayland::getCapabilities() const
|
|||
* is negligible. */
|
||||
GHOST_kCapabilityGPUReadFrontBuffer |
|
||||
/* This WAYLAND back-end has not yet implemented desktop color sample. */
|
||||
GHOST_kCapabilityDesktopSample));
|
||||
GHOST_kCapabilityDesktopSample |
|
||||
/* This flag will eventually be removed. */
|
||||
(has_wl_trackpad_physical_direction ? 0 : GHOST_kCapabilityTrackpadPhysicalDirection)));
|
||||
}
|
||||
|
||||
bool GHOST_SystemWayland::cursor_grab_use_software_display_get(const GHOST_TGrabCursorMode mode)
|
||||
|
|
|
@ -4693,6 +4693,12 @@ def km_grease_pencil_sculpt_mode(params):
|
|||
{"properties": [("scalar", 0.9)]}),
|
||||
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
|
||||
{"properties": [("scalar", 1.0 / 0.9)]}),
|
||||
# Invoke sculpt operator
|
||||
("grease_pencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
|
||||
("grease_pencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS',
|
||||
"ctrl": True}, {"properties": [("mode", 'INVERT')]}),
|
||||
("grease_pencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS',
|
||||
"shift": True}, {"properties": [("mode", 'SMOOTH')]}),
|
||||
*_template_paint_radial_control("gpencil_sculpt_paint"),
|
||||
])
|
||||
|
||||
|
@ -7138,21 +7144,53 @@ def km_image_editor_tool_uv_rip_region(params):
|
|||
)
|
||||
|
||||
|
||||
def km_image_editor_tool_uv_sculpt_stroke(params):
|
||||
def km_image_editor_tool_uv_grab(params):
|
||||
return (
|
||||
"Image Editor Tool: Uv, Sculpt Stroke",
|
||||
"Image Editor Tool: Uv, Grab",
|
||||
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("sculpt.uv_sculpt_stroke", {"type": params.tool_mouse, "value": 'PRESS'}, None),
|
||||
("sculpt.uv_sculpt_stroke", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("mode", 'INVERT')]}),
|
||||
("sculpt.uv_sculpt_stroke", {"type": params.tool_mouse, "value": 'PRESS', "shift": True},
|
||||
{"properties": [("mode", 'RELAX')]}),
|
||||
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
|
||||
{"properties": [("scalar", 0.9)]}),
|
||||
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
|
||||
{"properties": [("scalar", 1.0 / 0.9)]}),
|
||||
*_template_paint_radial_control("uv_sculpt"),
|
||||
("sculpt.uv_sculpt_grab", {"type": params.tool_mouse, "value": 'PRESS'}, None),
|
||||
("sculpt.uv_sculpt_grab", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("use_invert", True)]}),
|
||||
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS', "shift": True}, None),
|
||||
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
|
||||
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.size"), ], }),
|
||||
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.strength"), ], }),
|
||||
]},
|
||||
)
|
||||
|
||||
|
||||
def km_image_editor_tool_uv_relax(params):
|
||||
return (
|
||||
"Image Editor Tool: Uv, Relax",
|
||||
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS'}, None),
|
||||
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("use_invert", True)]}),
|
||||
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS', "shift": True}, None),
|
||||
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
|
||||
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.size"), ], }),
|
||||
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.strength"), ], }),
|
||||
]},
|
||||
)
|
||||
|
||||
|
||||
def km_image_editor_tool_uv_pinch(params):
|
||||
return (
|
||||
"Image Editor Tool: Uv, Pinch",
|
||||
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("sculpt.uv_sculpt_pinch", {"type": params.tool_mouse, "value": 'PRESS'}, None),
|
||||
("sculpt.uv_sculpt_pinch", {"type": params.tool_mouse, "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("use_invert", True)]}),
|
||||
("sculpt.uv_sculpt_relax", {"type": params.tool_mouse, "value": 'PRESS', "shift": True}, None),
|
||||
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
|
||||
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.size"), ], }),
|
||||
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("data_path_primary", "tool_settings.uv_sculpt.strength"), ], }),
|
||||
]},
|
||||
)
|
||||
|
||||
|
@ -8914,7 +8952,9 @@ def generate_keymaps(params=None):
|
|||
*(km_image_editor_tool_uv_select_circle(params, fallback=fallback) for fallback in (False, True)),
|
||||
*(km_image_editor_tool_uv_select_lasso(params, fallback=fallback) for fallback in (False, True)),
|
||||
km_image_editor_tool_uv_rip_region(params),
|
||||
km_image_editor_tool_uv_sculpt_stroke(params),
|
||||
km_image_editor_tool_uv_grab(params),
|
||||
km_image_editor_tool_uv_relax(params),
|
||||
km_image_editor_tool_uv_pinch(params),
|
||||
km_image_editor_tool_uv_move(params),
|
||||
km_image_editor_tool_uv_rotate(params),
|
||||
km_image_editor_tool_uv_scale(params),
|
||||
|
|
|
@ -6,6 +6,7 @@ from __future__ import annotations
|
|||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
FileHandler,
|
||||
Operator,
|
||||
PropertyGroup,
|
||||
)
|
||||
|
@ -441,9 +442,27 @@ class NODE_OT_enum_definition_item_move(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
class NODE_FH_image_node(FileHandler):
|
||||
bl_idname = "NODE_FH_image_node"
|
||||
bl_label = "Image node"
|
||||
bl_import_operator = "node.add_file"
|
||||
bl_file_extensions = ";".join((*bpy.path.extensions_image, *bpy.path.extensions_movie))
|
||||
|
||||
@classmethod
|
||||
def poll_drop(cls, context):
|
||||
return (
|
||||
(context.area is not None) and
|
||||
(context.area.type == 'NODE_EDITOR') and
|
||||
(context.region is not None) and
|
||||
(context.region.type == 'WINDOW')
|
||||
)
|
||||
|
||||
|
||||
classes = (
|
||||
NodeSetting,
|
||||
|
||||
NODE_FH_image_node,
|
||||
|
||||
NODE_OT_add_node,
|
||||
NODE_OT_add_simulation_zone,
|
||||
NODE_OT_add_repeat_zone,
|
||||
|
|
|
@ -292,9 +292,13 @@ class NODE_MT_geometry_node_GEO_INPUT_SCENE(Menu):
|
|||
node_add_menu.add_node_type(layout, "GeometryNodeIsViewport")
|
||||
if context.preferences.experimental.use_grease_pencil_version3:
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeInputNamedLayerSelection")
|
||||
if context.space_data.geometry_nodes_type == 'TOOL':
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeToolMousePosition")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeObjectInfo")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeInputSceneTime")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSelfObject")
|
||||
if context.space_data.geometry_nodes_type == 'TOOL':
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeViewportTransform")
|
||||
node_add_menu.draw_assets_for_catalog(layout, "Input/Scene")
|
||||
|
||||
|
||||
|
|
|
@ -1287,23 +1287,29 @@ class CLIP_PT_tools_grease_pencil_draw(AnnotationDrawingToolsPanel, Panel):
|
|||
|
||||
|
||||
class CLIP_MT_view_zoom(Menu):
|
||||
bl_label = "Fractional Zoom"
|
||||
bl_label = "Zoom"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
from math import isclose
|
||||
|
||||
current_zoom = _context.space_data.zoom_percentage
|
||||
ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
|
||||
|
||||
for i, (a, b) in enumerate(ratios):
|
||||
if i in {3, 4}: # Draw separators around Zoom 1:1.
|
||||
layout.separator()
|
||||
|
||||
percent = a / b * 100
|
||||
layout.operator(
|
||||
"clip.view_zoom_ratio",
|
||||
text=iface_("Zoom %d:%d") % (a, b),
|
||||
text=iface_("%g%% (%d:%d)") % (percent, a, b),
|
||||
translate=False,
|
||||
icon=('NONE', 'LAYER_ACTIVE')[isclose(percent, current_zoom, abs_tol=0.5)]
|
||||
).ratio = a / b
|
||||
|
||||
layout.separator()
|
||||
layout.operator("clip.view_zoom_in")
|
||||
layout.operator("clip.view_zoom_out")
|
||||
layout.operator("clip.view_all", text="Zoom to Fit").fit_view = True
|
||||
|
||||
|
||||
class CLIP_MT_view(Menu):
|
||||
bl_label = "View"
|
||||
|
@ -1319,26 +1325,20 @@ class CLIP_MT_view(Menu):
|
|||
layout.prop(sc, "show_region_hud")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("clip.view_selected")
|
||||
layout.operator("clip.view_all")
|
||||
layout.operator("clip.view_all", text="View Fit").fit_view = True
|
||||
layout.operator("clip.view_center_cursor")
|
||||
layout.menu("CLIP_MT_view_zoom")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("clip.view_zoom_in")
|
||||
layout.operator("clip.view_zoom_out")
|
||||
layout.separator()
|
||||
|
||||
layout.prop(sc, "show_metadata")
|
||||
layout.separator()
|
||||
|
||||
layout.operator("clip.view_all")
|
||||
layout.operator("clip.view_selected")
|
||||
layout.operator("clip.view_center_cursor")
|
||||
|
||||
layout.menu("CLIP_MT_view_zoom")
|
||||
else:
|
||||
layout.operator_context = 'INVOKE_REGION_PREVIEW'
|
||||
layout.operator("clip.graph_view_all")
|
||||
if sc.view == 'GRAPH':
|
||||
layout.operator("clip.graph_center_current_frame")
|
||||
|
||||
layout.operator("view2d.zoom_border", text="Zoom")
|
||||
layout.operator_context = 'INVOKE_DEFAULT'
|
||||
|
||||
layout.separator()
|
||||
|
|
|
@ -83,29 +83,16 @@ class IMAGE_MT_view(Menu):
|
|||
layout.prop(sima, "use_realtime_update")
|
||||
layout.prop(uv, "show_metadata")
|
||||
|
||||
if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
|
||||
layout.prop(uv, "show_texpaint")
|
||||
layout.prop(tool_settings, "show_uv_local_view", text="Show Same Material")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("image.view_zoom_in")
|
||||
layout.operator("image.view_zoom_out")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.menu("IMAGE_MT_view_zoom")
|
||||
|
||||
layout.separator()
|
||||
|
||||
if show_uvedit:
|
||||
layout.operator("image.view_selected", text="Frame Selected")
|
||||
|
||||
layout.operator("image.view_all")
|
||||
layout.operator("image.view_all", text="Frame All Fit").fit_view = True
|
||||
|
||||
layout.operator("image.view_center_cursor", text="Center View to Cursor")
|
||||
|
||||
layout.menu("IMAGE_MT_view_zoom")
|
||||
|
||||
layout.separator()
|
||||
|
||||
if show_render:
|
||||
|
@ -118,27 +105,38 @@ class IMAGE_MT_view(Menu):
|
|||
layout.operator("image.cycle_render_slot", text="Render Slot Cycle Previous").reverse = True
|
||||
layout.separator()
|
||||
|
||||
if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
|
||||
layout.prop(uv, "show_texpaint")
|
||||
layout.prop(tool_settings, "show_uv_local_view", text="Show Same Material")
|
||||
|
||||
layout.menu("INFO_MT_area")
|
||||
|
||||
|
||||
class IMAGE_MT_view_zoom(Menu):
|
||||
bl_label = "Fractional Zoom"
|
||||
bl_label = "Zoom"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
from math import isclose
|
||||
|
||||
current_zoom = _context.space_data.zoom_percentage
|
||||
ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
|
||||
|
||||
for i, (a, b) in enumerate(ratios):
|
||||
if i in {3, 4}: # Draw separators around Zoom 1:1.
|
||||
layout.separator()
|
||||
|
||||
percent = a / b * 100
|
||||
layout.operator(
|
||||
"image.view_zoom_ratio",
|
||||
text=iface_("Zoom %d:%d") % (a, b),
|
||||
text=iface_("%g%% (%d:%d)") % (percent, a, b),
|
||||
translate=False,
|
||||
icon=('NONE', 'LAYER_ACTIVE')[isclose(percent, current_zoom, abs_tol=0.5)]
|
||||
).ratio = a / b
|
||||
|
||||
layout.separator()
|
||||
layout.operator("image.view_zoom_in")
|
||||
layout.operator("image.view_zoom_out")
|
||||
layout.operator("image.view_all", text="Zoom to Fit").fit_view = True
|
||||
layout.operator("image.view_zoom_border", text="Zoom Region...")
|
||||
|
||||
|
||||
class IMAGE_MT_select(Menu):
|
||||
bl_label = "Select"
|
||||
|
@ -714,10 +712,6 @@ class IMAGE_HT_tool_header(Header):
|
|||
layout.popover("IMAGE_PT_tools_brush_display")
|
||||
layout.popover("IMAGE_PT_tools_brush_texture")
|
||||
layout.popover("IMAGE_PT_tools_mask_texture")
|
||||
elif tool_mode == 'UV':
|
||||
if (tool is not None) and tool.has_datablock:
|
||||
layout.popover("IMAGE_PT_uv_sculpt_curve")
|
||||
layout.popover("IMAGE_PT_uv_sculpt_options")
|
||||
|
||||
def draw_mode_settings(self, context):
|
||||
layout = self.layout
|
||||
|
@ -1344,50 +1338,21 @@ class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
|
|||
row.prop(ipaint, "tile_y", text="Y", toggle=True)
|
||||
|
||||
|
||||
class UVSculptPanel(UnifiedPaintPanel):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return cls.get_brush_mode(context) == 'UV_SCULPT'
|
||||
|
||||
|
||||
class IMAGE_PT_uv_sculpt_brush_select(Panel, BrushSelectPanel, ImagePaintPanel, UVSculptPanel):
|
||||
bl_context = ".uv_sculpt"
|
||||
bl_category = "Tool"
|
||||
bl_label = "Brushes"
|
||||
|
||||
|
||||
class IMAGE_PT_uv_sculpt_brush_settings(Panel, ImagePaintPanel, UVSculptPanel):
|
||||
bl_context = ".uv_sculpt"
|
||||
bl_category = "Tool"
|
||||
bl_label = "Brush Settings"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
tool_settings = context.tool_settings
|
||||
uvsculpt = tool_settings.uv_sculpt
|
||||
|
||||
brush = uvsculpt.brush
|
||||
|
||||
brush_settings(layout.column(), context, brush)
|
||||
|
||||
if brush:
|
||||
if brush.uv_sculpt_tool == 'RELAX':
|
||||
# Although this settings is stored in the scene,
|
||||
# it is only used by a single tool,
|
||||
# so it doesn't make sense from a user perspective to move it to the Options panel.
|
||||
layout.prop(tool_settings, "uv_relax_method")
|
||||
|
||||
|
||||
class IMAGE_PT_uv_sculpt_curve(Panel, FalloffPanel, ImagePaintPanel, UVSculptPanel):
|
||||
class IMAGE_PT_uv_sculpt_curve(Panel, ImagePaintPanel):
|
||||
bl_context = ".uv_sculpt" # Dot on purpose (access from top-bar).
|
||||
bl_parent_id = "IMAGE_PT_uv_sculpt_brush_settings"
|
||||
bl_category = "Tool"
|
||||
bl_label = "Falloff"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
props = context.scene.tool_settings.uv_sculpt
|
||||
layout.prop(props, "curve_preset", text="")
|
||||
if props.curve_preset == 'CUSTOM':
|
||||
layout.template_curve_mapping(props, "strength_curve")
|
||||
|
||||
class IMAGE_PT_uv_sculpt_options(Panel, ImagePaintPanel, UVSculptPanel):
|
||||
|
||||
class IMAGE_PT_uv_sculpt_options(Panel, ImagePaintPanel):
|
||||
bl_context = ".uv_sculpt" # Dot on purpose (access from top-bar).
|
||||
bl_category = "Tool"
|
||||
bl_label = "Options"
|
||||
|
@ -1396,12 +1361,10 @@ class IMAGE_PT_uv_sculpt_options(Panel, ImagePaintPanel, UVSculptPanel):
|
|||
layout = self.layout
|
||||
|
||||
tool_settings = context.tool_settings
|
||||
uvsculpt = tool_settings.uv_sculpt
|
||||
|
||||
col = layout.column()
|
||||
col.prop(tool_settings, "uv_sculpt_lock_borders")
|
||||
col.prop(tool_settings, "uv_sculpt_all_islands")
|
||||
col.prop(uvsculpt, "show_brush", text="Display Cursor")
|
||||
|
||||
|
||||
class ImageScopesPanel:
|
||||
|
@ -1776,8 +1739,6 @@ classes = (
|
|||
IMAGE_PT_paint_curve,
|
||||
IMAGE_PT_tools_brush_display,
|
||||
IMAGE_PT_tools_imagepaint_symmetry,
|
||||
IMAGE_PT_uv_sculpt_brush_select,
|
||||
IMAGE_PT_uv_sculpt_brush_settings,
|
||||
IMAGE_PT_uv_sculpt_options,
|
||||
IMAGE_PT_uv_sculpt_curve,
|
||||
IMAGE_PT_view_histogram,
|
||||
|
|
|
@ -171,6 +171,7 @@ class NODE_HT_header(Header):
|
|||
if snode.node_tree:
|
||||
layout.popover(panel="NODE_PT_geometry_node_tool_object_types", text="Types")
|
||||
layout.popover(panel="NODE_PT_geometry_node_tool_mode", text="Modes")
|
||||
layout.popover(panel="NODE_PT_geometry_node_tool_options", text="Options")
|
||||
display_pin = False
|
||||
else:
|
||||
# Custom node tree is edited as independent ID block
|
||||
|
@ -490,6 +491,21 @@ class NODE_PT_geometry_node_tool_mode(Panel):
|
|||
row.prop(group, prop, text="")
|
||||
|
||||
|
||||
class NODE_PT_geometry_node_tool_options(Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Options"
|
||||
bl_ui_units_x = 8
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
snode = context.space_data
|
||||
group = snode.node_tree
|
||||
|
||||
layout.prop(group, "use_wait_for_click")
|
||||
|
||||
|
||||
class NODE_PT_node_color_presets(PresetPanel, Panel):
|
||||
"""Predefined node color"""
|
||||
bl_label = "Color Presets"
|
||||
|
@ -1320,6 +1336,7 @@ classes = (
|
|||
NODE_PT_material_slots,
|
||||
NODE_PT_geometry_node_tool_object_types,
|
||||
NODE_PT_geometry_node_tool_mode,
|
||||
NODE_PT_geometry_node_tool_options,
|
||||
NODE_PT_node_color_presets,
|
||||
NODE_MT_node_tree_interface_context_menu,
|
||||
NODE_PT_node_tree_interface,
|
||||
|
|
|
@ -366,24 +366,30 @@ class SEQUENCER_MT_range(Menu):
|
|||
|
||||
|
||||
class SEQUENCER_MT_preview_zoom(Menu):
|
||||
bl_label = "Fractional Zoom"
|
||||
bl_label = "Zoom"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_PREVIEW'
|
||||
from math import isclose
|
||||
|
||||
current_zoom = _context.space_data.zoom_percentage
|
||||
ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
|
||||
|
||||
for i, (a, b) in enumerate(ratios):
|
||||
if i in {3, 4}: # Draw separators around Zoom 1:1.
|
||||
layout.separator()
|
||||
percent = a / b * 100
|
||||
|
||||
layout.operator(
|
||||
"sequencer.view_zoom_ratio",
|
||||
text=iface_("Zoom %d:%d") % (a, b),
|
||||
text=iface_("%g%% (%d:%d)") % (percent, a, b),
|
||||
translate=False,
|
||||
icon=('NONE', 'LAYER_ACTIVE')[isclose(percent, current_zoom, abs_tol=0.5)],
|
||||
).ratio = a / b
|
||||
layout.operator_context = 'INVOKE_DEFAULT'
|
||||
|
||||
layout.separator()
|
||||
layout.operator("view2d.zoom_in")
|
||||
layout.operator("view2d.zoom_out")
|
||||
layout.operator("view2d.zoom_border", text="Zoom Region...")
|
||||
|
||||
|
||||
class SEQUENCER_MT_proxy(Menu):
|
||||
|
@ -444,7 +450,6 @@ class SEQUENCER_MT_view(Menu):
|
|||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("sequencer.view_all")
|
||||
layout.operator("sequencer.view_frame")
|
||||
layout.operator("view2d.zoom_border", text="Zoom to Border")
|
||||
layout.prop(st, "use_clamp_view")
|
||||
|
||||
if is_preview:
|
||||
|
@ -453,12 +458,10 @@ class SEQUENCER_MT_view(Menu):
|
|||
layout.operator_context = 'INVOKE_REGION_PREVIEW'
|
||||
layout.operator("sequencer.view_all_preview", text="Fit Preview in Window")
|
||||
if is_sequencer_view:
|
||||
layout.menu("SEQUENCER_MT_preview_zoom", text="Fractional Preview Zoom")
|
||||
layout.menu("SEQUENCER_MT_preview_zoom", text="Preview Zoom")
|
||||
else:
|
||||
layout.operator("view2d.zoom_border", text="Zoom to Border")
|
||||
layout.menu("SEQUENCER_MT_preview_zoom")
|
||||
layout.prop(st, "use_zoom_to_fit")
|
||||
|
||||
layout.prop(st, "use_zoom_to_fit", text="Auto Zoom")
|
||||
layout.separator()
|
||||
layout.menu("SEQUENCER_MT_proxy")
|
||||
layout.operator_context = 'INVOKE_DEFAULT'
|
||||
|
|
|
@ -2181,36 +2181,82 @@ class _defs_image_uv_edit:
|
|||
|
||||
class _defs_image_uv_sculpt:
|
||||
|
||||
@staticmethod
|
||||
def generate_from_brushes(context):
|
||||
def draw_cursor(context, _tool, xy):
|
||||
@ToolDef.from_fn
|
||||
def grab():
|
||||
def draw_settings(context, layout, tool):
|
||||
uv_sculpt = context.scene.tool_settings.uv_sculpt
|
||||
layout.prop(uv_sculpt, "size")
|
||||
layout.prop(uv_sculpt, "strength")
|
||||
layout.popover("IMAGE_PT_uv_sculpt_curve")
|
||||
layout.popover("IMAGE_PT_uv_sculpt_options")
|
||||
|
||||
def draw_cursor(context, tool, xy):
|
||||
from gpu_extras.presets import draw_circle_2d
|
||||
tool_settings = context.tool_settings
|
||||
uv_sculpt = tool_settings.uv_sculpt
|
||||
if not uv_sculpt.show_brush:
|
||||
return
|
||||
ups = tool_settings.unified_paint_settings
|
||||
if ups.use_unified_size:
|
||||
radius = ups.size
|
||||
else:
|
||||
brush = tool_settings.uv_sculpt.brush
|
||||
if brush is None:
|
||||
return
|
||||
radius = brush.size
|
||||
uv_sculpt = context.scene.tool_settings.uv_sculpt
|
||||
radius = uv_sculpt.size
|
||||
draw_circle_2d(xy, (1.0,) * 4, radius)
|
||||
|
||||
return generate_from_enum_ex(
|
||||
context,
|
||||
idname_prefix="builtin_brush.",
|
||||
icon_prefix="brush.uv_sculpt.",
|
||||
type=bpy.types.Brush,
|
||||
attr="uv_sculpt_tool",
|
||||
tooldef_keywords=dict(
|
||||
operator="sculpt.uv_sculpt_stroke",
|
||||
keymap="Image Editor Tool: Uv, Sculpt Stroke",
|
||||
draw_cursor=draw_cursor,
|
||||
options={'KEYMAP_FALLBACK'},
|
||||
),
|
||||
return dict(
|
||||
idname="sculpt.uv_sculpt_grab",
|
||||
label="Grab",
|
||||
icon="brush.uv_sculpt.grab",
|
||||
keymap=(),
|
||||
draw_cursor=draw_cursor,
|
||||
draw_settings=draw_settings,
|
||||
options={'KEYMAP_FALLBACK'},
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def relax():
|
||||
def draw_settings(context, layout, tool):
|
||||
uv_sculpt = context.scene.tool_settings.uv_sculpt
|
||||
layout.prop(uv_sculpt, "size")
|
||||
layout.prop(uv_sculpt, "strength")
|
||||
layout.popover("IMAGE_PT_uv_sculpt_curve")
|
||||
layout.popover("IMAGE_PT_uv_sculpt_options")
|
||||
|
||||
props = tool.operator_properties("sculpt.uv_sculpt_relax")
|
||||
layout.prop(props, "relax_method", text="Method")
|
||||
|
||||
def draw_cursor(context, tool, xy):
|
||||
from gpu_extras.presets import draw_circle_2d
|
||||
uv_sculpt = context.scene.tool_settings.uv_sculpt
|
||||
radius = uv_sculpt.size
|
||||
draw_circle_2d(xy, (1.0,) * 4, radius)
|
||||
|
||||
return dict(
|
||||
idname="sculpt.uv_sculpt_relax",
|
||||
label="Relax",
|
||||
icon="brush.uv_sculpt.relax",
|
||||
keymap=(),
|
||||
draw_cursor=draw_cursor,
|
||||
draw_settings=draw_settings,
|
||||
options={'KEYMAP_FALLBACK'},
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def pinch():
|
||||
def draw_settings(context, layout, tool):
|
||||
uv_sculpt = context.scene.tool_settings.uv_sculpt
|
||||
layout.prop(uv_sculpt, "size")
|
||||
layout.prop(uv_sculpt, "strength")
|
||||
layout.popover("IMAGE_PT_uv_sculpt_curve")
|
||||
layout.popover("IMAGE_PT_uv_sculpt_options")
|
||||
|
||||
def draw_cursor(context, tool, xy):
|
||||
from gpu_extras.presets import draw_circle_2d
|
||||
uv_sculpt = context.scene.tool_settings.uv_sculpt
|
||||
radius = uv_sculpt.size
|
||||
draw_circle_2d(xy, (1.0,) * 4, radius)
|
||||
|
||||
return dict(
|
||||
idname="sculpt.uv_sculpt_pinch",
|
||||
label="Pinch",
|
||||
icon="brush.uv_sculpt.pinch",
|
||||
keymap=(),
|
||||
draw_cursor=draw_cursor,
|
||||
draw_settings=draw_settings,
|
||||
options={'KEYMAP_FALLBACK'},
|
||||
)
|
||||
|
||||
|
||||
|
@ -3014,11 +3060,9 @@ class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
|
|||
None,
|
||||
_defs_image_uv_edit.rip_region,
|
||||
None,
|
||||
lambda context: (
|
||||
_defs_image_uv_sculpt.generate_from_brushes(context)
|
||||
if _defs_image_generic.poll_uvedit(context)
|
||||
else ()
|
||||
),
|
||||
_defs_image_uv_sculpt.grab,
|
||||
_defs_image_uv_sculpt.relax,
|
||||
_defs_image_uv_sculpt.pinch,
|
||||
],
|
||||
'MASK': [
|
||||
None,
|
||||
|
|
|
@ -1795,6 +1795,13 @@ class USERPREF_PT_input_touchpad(InputPanel, CenterAlignMixIn, Panel):
|
|||
col = layout.column()
|
||||
col.prop(inputs, "use_multitouch_gestures")
|
||||
|
||||
from _bpy import _wm_capabilities
|
||||
capabilities = _wm_capabilities()
|
||||
if not capabilities['TRACKPAD_PHYSICAL_DIRECTION']:
|
||||
row = col.row()
|
||||
row.active = inputs.use_multitouch_gestures
|
||||
row.prop(inputs, "touchpad_scroll_direction", text="Scroll Direction")
|
||||
|
||||
|
||||
class USERPREF_PT_input_tablet(InputPanel, CenterAlignMixIn, Panel):
|
||||
bl_label = "Tablet"
|
||||
|
|
|
@ -474,9 +474,14 @@ class _draw_tool_settings_context_mode:
|
|||
)
|
||||
|
||||
# direction
|
||||
if not capabilities.has_direction:
|
||||
if brush.gpencil_sculpt_tool in {'THICKNESS', 'STRENGTH', 'PINCH', 'TWIST'}:
|
||||
layout.row().prop(brush, "direction", expand=True, text="")
|
||||
|
||||
# Brush falloff
|
||||
layout.popover("VIEW3D_PT_tools_brush_falloff")
|
||||
|
||||
# Active layer only switch
|
||||
layout.prop(brush.gpencil_settings, "use_active_layer_only")
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
|
@ -894,11 +899,11 @@ class VIEW3D_HT_header(Header):
|
|||
row = layout.row(align=True)
|
||||
row.prop(tool_settings, "use_gpencil_draw_additive", text="", icon='FREEZE')
|
||||
|
||||
if object_mode in {'PAINT_GPENCIL', 'EDIT', 'WEIGHT_GPENCIL'}:
|
||||
if object_mode in {'PAINT_GPENCIL', 'EDIT', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
|
||||
row = layout.row(align=True)
|
||||
row.prop(tool_settings, "use_grease_pencil_multi_frame_editing", text="")
|
||||
|
||||
if object_mode in {'EDIT', 'WEIGHT_GPENCIL'}:
|
||||
if object_mode in {'EDIT', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
|
||||
sub = row.row(align=True)
|
||||
sub.enabled = tool_settings.use_grease_pencil_multi_frame_editing
|
||||
sub.popover(
|
||||
|
@ -975,6 +980,35 @@ class VIEW3D_HT_header(Header):
|
|||
text="Multiframe",
|
||||
)
|
||||
|
||||
# Grease Pencil
|
||||
if obj and obj.type == 'GREASEPENCIL':
|
||||
if object_mode == 'PAINT_GREASE_PENCIL':
|
||||
row = layout.row()
|
||||
sub = row.row(align=True)
|
||||
sub.prop(tool_settings, "use_gpencil_draw_onback", text="", icon='MOD_OPACITY')
|
||||
sub.separator(factor=0.4)
|
||||
sub.prop(tool_settings, "use_gpencil_automerge_strokes", text="")
|
||||
sub.separator(factor=0.4)
|
||||
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')
|
||||
|
||||
# Select mode for Editing
|
||||
if object_mode == 'EDIT':
|
||||
row = layout.row(align=True)
|
||||
row.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='POINT')
|
||||
row.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='STROKE')
|
||||
|
||||
subrow = row.row(align=True)
|
||||
subrow.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='SEGMENT')
|
||||
|
||||
# Select mode for Sculpt
|
||||
if object_mode == 'SCULPT_GPENCIL':
|
||||
row = layout.row(align=True)
|
||||
row.prop(tool_settings, "use_gpencil_select_mask_point", text="")
|
||||
row.prop(tool_settings, "use_gpencil_select_mask_stroke", text="")
|
||||
row.prop(tool_settings, "use_gpencil_select_mask_segment", text="")
|
||||
|
||||
overlay = view.overlay
|
||||
|
||||
VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
|
||||
|
@ -1188,7 +1222,12 @@ class VIEW3D_MT_editor_menus(Menu):
|
|||
mode_string = context.mode
|
||||
edit_object = context.edit_object
|
||||
gp_edit = obj and obj.type == 'GPENCIL' and obj.mode in {
|
||||
'EDIT_GPENCIL', 'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL', 'VERTEX_GPENCIL',
|
||||
'EDIT_GPENCIL',
|
||||
'PAINT_GPENCIL',
|
||||
'SCULPT_GPENCIL',
|
||||
'SCULPT_GREASE_PENCIL',
|
||||
'WEIGHT_GPENCIL',
|
||||
'VERTEX_GPENCIL',
|
||||
}
|
||||
tool_settings = context.tool_settings
|
||||
|
||||
|
@ -1196,18 +1235,16 @@ class VIEW3D_MT_editor_menus(Menu):
|
|||
|
||||
# Select Menu
|
||||
if gp_edit:
|
||||
if mode_string not in {'PAINT_GPENCIL', 'WEIGHT_GPENCIL'}:
|
||||
if (
|
||||
mode_string == 'SCULPT_GPENCIL' and
|
||||
(tool_settings.use_gpencil_select_mask_point or
|
||||
tool_settings.use_gpencil_select_mask_stroke or
|
||||
tool_settings.use_gpencil_select_mask_segment)
|
||||
):
|
||||
layout.menu("VIEW3D_MT_select_edit_gpencil")
|
||||
elif mode_string == 'EDIT_GPENCIL':
|
||||
layout.menu("VIEW3D_MT_select_edit_gpencil")
|
||||
elif mode_string == 'VERTEX_GPENCIL':
|
||||
layout.menu("VIEW3D_MT_select_edit_gpencil")
|
||||
use_gpencil_masking = (tool_settings.use_gpencil_select_mask_point or
|
||||
tool_settings.use_gpencil_select_mask_stroke or
|
||||
tool_settings.use_gpencil_select_mask_segment)
|
||||
if mode_string in {
|
||||
'EDIT_GPENCIL',
|
||||
'VERTEX_GPENCIL'} or (
|
||||
mode_string in {
|
||||
'SCULPT_GPENCIL',
|
||||
'SCULPT_GREASE_PENCIL'} and use_gpencil_masking):
|
||||
layout.menu("VIEW3D_MT_select_edit_gpencil")
|
||||
elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
|
||||
mesh = obj.data
|
||||
if mesh.use_paint_mask:
|
||||
|
|
|
@ -155,6 +155,14 @@ int clear_keyframe(Main *bmain,
|
|||
int array_index,
|
||||
eInsertKeyFlags /*flag*/);
|
||||
|
||||
/** Check if a flag is set for keyframing (per scene takes precedence). */
|
||||
bool is_keying_flag(const Scene *scene, eKeying_Flag flag);
|
||||
|
||||
/**
|
||||
* Get the settings for key-framing from the given scene.
|
||||
*/
|
||||
eInsertKeyFlags get_keyframing_flags(Scene *scene);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -173,9 +181,6 @@ bool is_autokey_on(const Scene *scene);
|
|||
/** Check the mode for auto-keyframing (per scene takes precedence). */
|
||||
bool is_autokey_mode(const Scene *scene, eAutokey_Mode mode);
|
||||
|
||||
/** Check if a flag is set for keyframing (per scene takes precedence). */
|
||||
bool is_keying_flag(const Scene *scene, eKeying_Flag flag);
|
||||
|
||||
/**
|
||||
* Auto-keyframing feature - checks for whether anything should be done for the current frame.
|
||||
*/
|
||||
|
|
|
@ -208,6 +208,27 @@ bool is_keying_flag(const Scene *scene, const eKeying_Flag flag)
|
|||
return U.keying_flag & flag;
|
||||
}
|
||||
|
||||
eInsertKeyFlags get_keyframing_flags(Scene *scene)
|
||||
{
|
||||
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
|
||||
|
||||
/* Visual keying. */
|
||||
if (is_keying_flag(scene, KEYING_FLAG_VISUALKEY)) {
|
||||
flag |= INSERTKEY_MATRIX;
|
||||
}
|
||||
|
||||
/* Cycle-aware keyframe insertion - preserve cycle period and flow. */
|
||||
if (is_keying_flag(scene, KEYING_FLAG_CYCLEAWARE)) {
|
||||
flag |= INSERTKEY_CYCLE_AWARE;
|
||||
}
|
||||
|
||||
if (is_keying_flag(scene, MANUALKEY_FLAG_INSERTNEEDED)) {
|
||||
flag |= INSERTKEY_NEEDED;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/** Used to make curves newly added to a cyclic Action cycle with the correct period. */
|
||||
static void make_new_fcurve_cyclic(FCurve *fcu, const blender::float2 &action_range)
|
||||
{
|
||||
|
|
|
@ -71,9 +71,7 @@ static void blf_load_datafiles_dir()
|
|||
}
|
||||
|
||||
const char *filepath = file_list[i].path;
|
||||
if (!BLI_path_extension_check_n(
|
||||
filepath, ".ttf", ".ttc", ".otf", ".otc", ".woff", ".woff2", nullptr))
|
||||
{
|
||||
if (!BLI_path_extension_check_n(filepath, ".ttf", ".otf", ".woff", ".woff2", nullptr)) {
|
||||
continue;
|
||||
}
|
||||
if (BLF_is_loaded(filepath)) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* General operations for brushes.
|
||||
*/
|
||||
|
||||
#include "DNA_brush_enums.h"
|
||||
#include "DNA_color_types.h"
|
||||
#include "DNA_object_enums.h"
|
||||
|
||||
|
@ -93,6 +94,10 @@ float BKE_brush_curve_strength_clamped(const Brush *br, float p, float len);
|
|||
/**
|
||||
* Uses the brush curve control to find a strength value.
|
||||
*/
|
||||
float BKE_brush_curve_strength(eBrushCurvePreset preset,
|
||||
const CurveMapping *cumap,
|
||||
float distance,
|
||||
float brush_radius);
|
||||
float BKE_brush_curve_strength(const Brush *br, float p, float len);
|
||||
|
||||
/* Sampling. */
|
||||
|
|
|
@ -35,6 +35,16 @@ namespace blender::bke {
|
|||
|
||||
namespace greasepencil {
|
||||
|
||||
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px`
|
||||
* was the brush size which would be stored in the stroke thickness and then scaled by the
|
||||
* point pressure factor. Finally, the render engine would divide this thickness value by
|
||||
* 2000 (we're going from a thickness to a radius, hence the factor of two) to convert back
|
||||
* into blender units. With Grease Pencil 3, the radius is no longer stored in `px` space,
|
||||
* but in blender units (world space) directly. Also note that there is no longer a stroke
|
||||
* "thickness" attribute, the radii are directly stored on the points.
|
||||
* For compatibility, legacy thickness values have to be multiplied by this factor. */
|
||||
constexpr float LEGACY_RADIUS_CONVERSION_FACTOR = 1.0f / 2000.0f;
|
||||
|
||||
class DrawingRuntime {
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -1278,6 +1278,8 @@ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index
|
|||
#define GEO_NODE_GRID_TO_MESH 2129
|
||||
#define GEO_NODE_DISTRIBUTE_POINTS_IN_GRID 2130
|
||||
#define GEO_NODE_SDF_GRID_BOOLEAN 2131
|
||||
#define GEO_NODE_TOOL_VIEWPORT_TRANSFORM 2132
|
||||
#define GEO_NODE_TOOL_MOUSE_POSITION 2133
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -96,7 +96,6 @@ enum class PaintMode : int8_t {
|
|||
Texture3D = 3,
|
||||
/** Image space (2D painting). */
|
||||
Texture2D = 4,
|
||||
SculptUV = 5,
|
||||
GPencil = 6,
|
||||
/* Grease Pencil Vertex Paint */
|
||||
VertexGPencil = 7,
|
||||
|
@ -111,8 +110,6 @@ enum class PaintMode : int8_t {
|
|||
Invalid = 12,
|
||||
};
|
||||
|
||||
#define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PaintMode::SculptUV)
|
||||
|
||||
/* overlay invalidation */
|
||||
enum ePaintOverlayControlFlags {
|
||||
PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY = 1,
|
||||
|
@ -291,18 +288,17 @@ struct SculptPoseIKChainSegment {
|
|||
float len;
|
||||
blender::float3 scale;
|
||||
float rot[4];
|
||||
float *weights;
|
||||
blender::Array<float> weights;
|
||||
|
||||
/* Store a 4x4 transform matrix for each of the possible combinations of enabled XYZ symmetry
|
||||
* axis. */
|
||||
float trans_mat[PAINT_SYMM_AREAS][4][4];
|
||||
float pivot_mat[PAINT_SYMM_AREAS][4][4];
|
||||
float pivot_mat_inv[PAINT_SYMM_AREAS][4][4];
|
||||
std::array<blender::float4x4, PAINT_SYMM_AREAS> trans_mat;
|
||||
std::array<blender::float4x4, PAINT_SYMM_AREAS> pivot_mat;
|
||||
std::array<blender::float4x4, PAINT_SYMM_AREAS> pivot_mat_inv;
|
||||
};
|
||||
|
||||
struct SculptPoseIKChain {
|
||||
SculptPoseIKChainSegment *segments;
|
||||
int tot_segments;
|
||||
blender::Array<SculptPoseIKChainSegment> segments;
|
||||
blender::float3 grab_delta_offset;
|
||||
};
|
||||
|
||||
|
@ -587,7 +583,7 @@ struct SculptSession {
|
|||
|
||||
/* Pose Brush Preview */
|
||||
blender::float3 pose_origin;
|
||||
SculptPoseIKChain *pose_ik_chain_preview;
|
||||
std::unique_ptr<SculptPoseIKChain> pose_ik_chain_preview;
|
||||
|
||||
/* Boundary Brush Preview */
|
||||
SculptBoundary *boundary_preview;
|
||||
|
|
|
@ -2531,20 +2531,24 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
|
|||
}
|
||||
}
|
||||
|
||||
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
|
||||
float BKE_brush_curve_strength(const eBrushCurvePreset preset,
|
||||
const CurveMapping *cumap,
|
||||
const float distance,
|
||||
const float brush_radius)
|
||||
{
|
||||
float p = distance;
|
||||
float strength = 1.0f;
|
||||
|
||||
if (p >= len) {
|
||||
if (p >= brush_radius) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = p / len;
|
||||
p = p / brush_radius;
|
||||
p = 1.0f - p;
|
||||
|
||||
switch (br->curve_preset) {
|
||||
switch (preset) {
|
||||
case BRUSH_CURVE_CUSTOM:
|
||||
strength = BKE_curvemapping_evaluateF(br->curve, 0, 1.0f - p);
|
||||
strength = BKE_curvemapping_evaluateF(cumap, 0, 1.0f - p);
|
||||
break;
|
||||
case BRUSH_CURVE_SHARP:
|
||||
strength = p * p;
|
||||
|
@ -2578,6 +2582,11 @@ float BKE_brush_curve_strength(const Brush *br, float p, const float len)
|
|||
return strength;
|
||||
}
|
||||
|
||||
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
|
||||
{
|
||||
return BKE_brush_curve_strength(eBrushCurvePreset(br->curve_preset), br->curve, p, len);
|
||||
}
|
||||
|
||||
float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len)
|
||||
{
|
||||
float strength = BKE_brush_curve_strength(br, p, len);
|
||||
|
|
|
@ -813,13 +813,7 @@ static void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
|
|||
BLI_assert(points.size() == gps->totpoints);
|
||||
|
||||
const Span<bGPDspoint> src_points{gps->points, gps->totpoints};
|
||||
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px`
|
||||
* was the brush size which would be stored in the stroke thickness and then scaled by the
|
||||
* point pressure factor. Finally, the render engine would divide this thickness value by
|
||||
* 2000 (we're going from a thickness to a radius, hence the factor of two) to convert back
|
||||
* into blender units. Store the radius now directly in blender units. This makes it
|
||||
* consistent with how hair curves handle the radius. */
|
||||
const float stroke_thickness = float(gps->thickness) / 2000.0f;
|
||||
const float stroke_thickness = float(gps->thickness) * LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
MutableSpan<float3> dst_positions = positions.slice(points);
|
||||
MutableSpan<float3> dst_handle_positions_left = has_bezier_stroke ?
|
||||
handle_positions_left.slice(points) :
|
||||
|
@ -1213,6 +1207,61 @@ static void thickness_factor_to_modifier(ConversionData &conversion_data,
|
|||
animdata_thickness_transfer.fcurves_convert_finalize();
|
||||
}
|
||||
|
||||
static void fcurve_convert_thickness_cb(FCurve &fcurve)
|
||||
{
|
||||
if (fcurve.bezt) {
|
||||
for (uint i = 0; i < fcurve.totvert; i++) {
|
||||
BezTriple &bezier_triple = fcurve.bezt[i];
|
||||
bezier_triple.vec[0][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
bezier_triple.vec[1][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
bezier_triple.vec[2][1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
}
|
||||
}
|
||||
if (fcurve.fpt) {
|
||||
for (uint i = 0; i < fcurve.totvert; i++) {
|
||||
FPoint &fpoint = fcurve.fpt[i];
|
||||
fpoint.vec[1] *= LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
}
|
||||
}
|
||||
fcurve.flag &= ~FCURVE_INT_VALUES;
|
||||
BKE_fcurve_handles_recalc(&fcurve);
|
||||
}
|
||||
|
||||
static void legacy_object_thickness_modifier_thickness_anim(ConversionData &conversion_data,
|
||||
Object &object)
|
||||
{
|
||||
if (BKE_animdata_from_id(&object.id) == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note: At this point, the animation was already transferred to the destination object. Now we
|
||||
* just need to convert the fcurve data to be in the right space. */
|
||||
AnimDataConvertor animdata_convert_thickness(
|
||||
conversion_data,
|
||||
object.id,
|
||||
object.id,
|
||||
{{".thickness", ".thickness", fcurve_convert_thickness_cb}});
|
||||
|
||||
LISTBASE_FOREACH (ModifierData *, tmd, &object.modifiers) {
|
||||
if (ModifierType(tmd->type) != eModifierType_GreasePencilThickness) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char modifier_name[MAX_NAME * 2];
|
||||
BLI_str_escape(modifier_name, tmd->name, sizeof(modifier_name));
|
||||
animdata_convert_thickness.root_path_src = fmt::format("modifiers[\"{}\"]", modifier_name);
|
||||
animdata_convert_thickness.root_path_dst = fmt::format("modifiers[\"{}\"]", modifier_name);
|
||||
|
||||
if (!animdata_convert_thickness.source_has_animation_to_convert()) {
|
||||
continue;
|
||||
}
|
||||
animdata_convert_thickness.fcurves_convert();
|
||||
}
|
||||
|
||||
animdata_convert_thickness.fcurves_convert_finalize();
|
||||
DEG_relations_tag_update(&conversion_data.bmain);
|
||||
}
|
||||
|
||||
static void layer_adjustments_to_modifiers(ConversionData &conversion_data,
|
||||
bGPdata &src_object_data,
|
||||
Object &dst_object)
|
||||
|
@ -1225,26 +1274,6 @@ static void layer_adjustments_to_modifiers(ConversionData &conversion_data,
|
|||
src_object_data.id,
|
||||
{{".tint_color", ".color"}, {".tint_factor", ".factor"}});
|
||||
|
||||
/* Ensure values are divided by 2k, to match conversion done for non-animated value. */
|
||||
constexpr float thickness_adjustement_factor = 1.0f / 2000.0f;
|
||||
auto fcurve_convert_thickness_cb = [&](FCurve &fcurve) {
|
||||
if (fcurve.bezt) {
|
||||
for (uint i = 0; i < fcurve.totvert; i++) {
|
||||
BezTriple &bezier_triple = fcurve.bezt[i];
|
||||
bezier_triple.vec[0][1] *= thickness_adjustement_factor;
|
||||
bezier_triple.vec[1][1] *= thickness_adjustement_factor;
|
||||
bezier_triple.vec[2][1] *= thickness_adjustement_factor;
|
||||
}
|
||||
}
|
||||
if (fcurve.fpt) {
|
||||
for (uint i = 0; i < fcurve.totvert; i++) {
|
||||
FPoint &fpoint = fcurve.fpt[i];
|
||||
fpoint.vec[1] *= thickness_adjustement_factor;
|
||||
}
|
||||
}
|
||||
fcurve.flag &= ~FCURVE_INT_VALUES;
|
||||
BKE_fcurve_handles_recalc(&fcurve);
|
||||
};
|
||||
AnimDataConvertor animdata_thickness_transfer(
|
||||
conversion_data,
|
||||
dst_object.id,
|
||||
|
@ -1301,7 +1330,7 @@ static void layer_adjustments_to_modifiers(ConversionData &conversion_data,
|
|||
/* Convert the "pixel" offset value into a radius value.
|
||||
* GPv2 used a conversion of 1 "px" = 0.001. */
|
||||
/* Note: this offset may be negative. */
|
||||
const float radius_offset = float(thickness_px) * thickness_adjustement_factor;
|
||||
const float radius_offset = float(thickness_px) * LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
|
||||
const auto offset_radius_ntree_ensure = [&](Library *owner_library) {
|
||||
if (bNodeTree **ntree = conversion_data.offset_radius_ntree_by_library.lookup_ptr(
|
||||
|
@ -2252,7 +2281,7 @@ static void legacy_object_modifier_thickness(ConversionData &conversion_data,
|
|||
md_thickness.flag |= MOD_GREASE_PENCIL_THICK_WEIGHT_FACTOR;
|
||||
}
|
||||
md_thickness.thickness_fac = legacy_md_thickness.thickness_fac;
|
||||
md_thickness.thickness = legacy_md_thickness.thickness;
|
||||
md_thickness.thickness = legacy_md_thickness.thickness * LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
|
||||
legacy_object_modifier_influence(md_thickness.influence,
|
||||
legacy_md_thickness.layername,
|
||||
|
@ -2914,6 +2943,8 @@ static void legacy_gpencil_object_ex(ConversionData &conversion_data, Object &ob
|
|||
}
|
||||
|
||||
legacy_object_modifiers(conversion_data, object);
|
||||
/* Convert the animation of the "uniform thickness" setting of the thickness modifier. */
|
||||
legacy_object_thickness_modifier_thickness_anim(conversion_data, object);
|
||||
|
||||
/* Layer adjustments should be added after all other modifiers. */
|
||||
layer_adjustments_to_modifiers(conversion_data, *gpd, object);
|
||||
|
@ -2975,95 +3006,87 @@ void legacy_main(Main &bmain, BlendFileReadReport & /*reports*/)
|
|||
void lineart_wrap_v3(const LineartGpencilModifierData *lmd_legacy,
|
||||
GreasePencilLineartModifierData *lmd)
|
||||
{
|
||||
#define LMD_WRAP(var) lmd->var = lmd_legacy->var
|
||||
|
||||
LMD_WRAP(edge_types);
|
||||
LMD_WRAP(source_type);
|
||||
LMD_WRAP(use_multiple_levels);
|
||||
LMD_WRAP(level_start);
|
||||
LMD_WRAP(level_end);
|
||||
LMD_WRAP(source_camera);
|
||||
LMD_WRAP(light_contour_object);
|
||||
LMD_WRAP(source_object);
|
||||
LMD_WRAP(source_collection);
|
||||
LMD_WRAP(target_material);
|
||||
lmd->edge_types = lmd_legacy->edge_types;
|
||||
lmd->source_type = lmd_legacy->source_type;
|
||||
lmd->use_multiple_levels = lmd_legacy->use_multiple_levels;
|
||||
lmd->level_start = lmd_legacy->level_start;
|
||||
lmd->level_end = lmd_legacy->level_end;
|
||||
lmd->source_camera = lmd_legacy->source_camera;
|
||||
lmd->light_contour_object = lmd_legacy->light_contour_object;
|
||||
lmd->source_object = lmd_legacy->source_object;
|
||||
lmd->source_collection = lmd_legacy->source_collection;
|
||||
lmd->target_material = lmd_legacy->target_material;
|
||||
STRNCPY(lmd->source_vertex_group, lmd_legacy->source_vertex_group);
|
||||
STRNCPY(lmd->vgname, lmd_legacy->vgname);
|
||||
LMD_WRAP(overscan);
|
||||
LMD_WRAP(shadow_camera_fov);
|
||||
LMD_WRAP(shadow_camera_size);
|
||||
LMD_WRAP(shadow_camera_near);
|
||||
LMD_WRAP(shadow_camera_far);
|
||||
LMD_WRAP(opacity);
|
||||
lmd->overscan = lmd_legacy->overscan;
|
||||
lmd->shadow_camera_fov = lmd_legacy->shadow_camera_fov;
|
||||
lmd->shadow_camera_size = lmd_legacy->shadow_camera_size;
|
||||
lmd->shadow_camera_near = lmd_legacy->shadow_camera_near;
|
||||
lmd->shadow_camera_far = lmd_legacy->shadow_camera_far;
|
||||
lmd->opacity = lmd_legacy->opacity;
|
||||
lmd->thickness = lmd_legacy->thickness / 2;
|
||||
LMD_WRAP(mask_switches);
|
||||
LMD_WRAP(material_mask_bits);
|
||||
LMD_WRAP(intersection_mask);
|
||||
LMD_WRAP(shadow_selection);
|
||||
LMD_WRAP(silhouette_selection);
|
||||
LMD_WRAP(crease_threshold);
|
||||
LMD_WRAP(angle_splitting_threshold);
|
||||
LMD_WRAP(chain_smooth_tolerance);
|
||||
LMD_WRAP(chaining_image_threshold);
|
||||
LMD_WRAP(calculation_flags);
|
||||
LMD_WRAP(flags);
|
||||
LMD_WRAP(stroke_depth_offset);
|
||||
LMD_WRAP(level_start_override);
|
||||
LMD_WRAP(level_end_override);
|
||||
LMD_WRAP(edge_types_override);
|
||||
LMD_WRAP(shadow_selection_override);
|
||||
LMD_WRAP(shadow_use_silhouette_override);
|
||||
LMD_WRAP(cache);
|
||||
LMD_WRAP(la_data_ptr);
|
||||
|
||||
#undef LMD_WRAP
|
||||
lmd->mask_switches = lmd_legacy->mask_switches;
|
||||
lmd->material_mask_bits = lmd_legacy->material_mask_bits;
|
||||
lmd->intersection_mask = lmd_legacy->intersection_mask;
|
||||
lmd->shadow_selection = lmd_legacy->shadow_selection;
|
||||
lmd->silhouette_selection = lmd_legacy->silhouette_selection;
|
||||
lmd->crease_threshold = lmd_legacy->crease_threshold;
|
||||
lmd->angle_splitting_threshold = lmd_legacy->angle_splitting_threshold;
|
||||
lmd->chain_smooth_tolerance = lmd_legacy->chain_smooth_tolerance;
|
||||
lmd->chaining_image_threshold = lmd_legacy->chaining_image_threshold;
|
||||
lmd->calculation_flags = lmd_legacy->calculation_flags;
|
||||
lmd->flags = lmd_legacy->flags;
|
||||
lmd->stroke_depth_offset = lmd_legacy->stroke_depth_offset;
|
||||
lmd->level_start_override = lmd_legacy->level_start_override;
|
||||
lmd->level_end_override = lmd_legacy->level_end_override;
|
||||
lmd->edge_types_override = lmd_legacy->edge_types_override;
|
||||
lmd->shadow_selection_override = lmd_legacy->shadow_selection_override;
|
||||
lmd->shadow_use_silhouette_override = lmd_legacy->shadow_use_silhouette_override;
|
||||
lmd->cache = lmd_legacy->cache;
|
||||
lmd->la_data_ptr = lmd_legacy->la_data_ptr;
|
||||
}
|
||||
|
||||
void lineart_unwrap_v3(LineartGpencilModifierData *lmd_legacy,
|
||||
const GreasePencilLineartModifierData *lmd)
|
||||
{
|
||||
#define LMD_UNWRAP(var) lmd_legacy->var = lmd->var
|
||||
|
||||
LMD_UNWRAP(edge_types);
|
||||
LMD_UNWRAP(source_type);
|
||||
LMD_UNWRAP(use_multiple_levels);
|
||||
LMD_UNWRAP(level_start);
|
||||
LMD_UNWRAP(level_end);
|
||||
LMD_UNWRAP(source_camera);
|
||||
LMD_UNWRAP(light_contour_object);
|
||||
LMD_UNWRAP(source_object);
|
||||
LMD_UNWRAP(source_collection);
|
||||
LMD_UNWRAP(target_material);
|
||||
lmd_legacy->edge_types = lmd->edge_types;
|
||||
lmd_legacy->source_type = lmd->source_type;
|
||||
lmd_legacy->use_multiple_levels = lmd->use_multiple_levels;
|
||||
lmd_legacy->level_start = lmd->level_start;
|
||||
lmd_legacy->level_end = lmd->level_end;
|
||||
lmd_legacy->source_camera = lmd->source_camera;
|
||||
lmd_legacy->light_contour_object = lmd->light_contour_object;
|
||||
lmd_legacy->source_object = lmd->source_object;
|
||||
lmd_legacy->source_collection = lmd->source_collection;
|
||||
lmd_legacy->target_material = lmd->target_material;
|
||||
STRNCPY(lmd_legacy->source_vertex_group, lmd->source_vertex_group);
|
||||
STRNCPY(lmd_legacy->vgname, lmd->vgname);
|
||||
LMD_UNWRAP(overscan);
|
||||
LMD_UNWRAP(shadow_camera_fov);
|
||||
LMD_UNWRAP(shadow_camera_size);
|
||||
LMD_UNWRAP(shadow_camera_near);
|
||||
LMD_UNWRAP(shadow_camera_far);
|
||||
LMD_UNWRAP(opacity);
|
||||
lmd_legacy->overscan = lmd->overscan;
|
||||
lmd_legacy->shadow_camera_fov = lmd->shadow_camera_fov;
|
||||
lmd_legacy->shadow_camera_size = lmd->shadow_camera_size;
|
||||
lmd_legacy->shadow_camera_near = lmd->shadow_camera_near;
|
||||
lmd_legacy->shadow_camera_far = lmd->shadow_camera_far;
|
||||
lmd_legacy->opacity = lmd->opacity;
|
||||
lmd_legacy->thickness = lmd->thickness * 2;
|
||||
LMD_UNWRAP(mask_switches);
|
||||
LMD_UNWRAP(material_mask_bits);
|
||||
LMD_UNWRAP(intersection_mask);
|
||||
LMD_UNWRAP(shadow_selection);
|
||||
LMD_UNWRAP(silhouette_selection);
|
||||
LMD_UNWRAP(crease_threshold);
|
||||
LMD_UNWRAP(angle_splitting_threshold);
|
||||
LMD_UNWRAP(chain_smooth_tolerance);
|
||||
LMD_UNWRAP(chaining_image_threshold);
|
||||
LMD_UNWRAP(calculation_flags);
|
||||
LMD_UNWRAP(flags);
|
||||
LMD_UNWRAP(stroke_depth_offset);
|
||||
LMD_UNWRAP(level_start_override);
|
||||
LMD_UNWRAP(level_end_override);
|
||||
LMD_UNWRAP(edge_types_override);
|
||||
LMD_UNWRAP(shadow_selection_override);
|
||||
LMD_UNWRAP(shadow_use_silhouette_override);
|
||||
LMD_UNWRAP(cache);
|
||||
LMD_UNWRAP(la_data_ptr);
|
||||
|
||||
#undef LMD_UNWRAP
|
||||
lmd_legacy->mask_switches = lmd->mask_switches;
|
||||
lmd_legacy->material_mask_bits = lmd->material_mask_bits;
|
||||
lmd_legacy->intersection_mask = lmd->intersection_mask;
|
||||
lmd_legacy->shadow_selection = lmd->shadow_selection;
|
||||
lmd_legacy->silhouette_selection = lmd->silhouette_selection;
|
||||
lmd_legacy->crease_threshold = lmd->crease_threshold;
|
||||
lmd_legacy->angle_splitting_threshold = lmd->angle_splitting_threshold;
|
||||
lmd_legacy->chain_smooth_tolerance = lmd->chain_smooth_tolerance;
|
||||
lmd_legacy->chaining_image_threshold = lmd->chaining_image_threshold;
|
||||
lmd_legacy->calculation_flags = lmd->calculation_flags;
|
||||
lmd_legacy->flags = lmd->flags;
|
||||
lmd_legacy->stroke_depth_offset = lmd->stroke_depth_offset;
|
||||
lmd_legacy->level_start_override = lmd->level_start_override;
|
||||
lmd_legacy->level_end_override = lmd->level_end_override;
|
||||
lmd_legacy->edge_types_override = lmd->edge_types_override;
|
||||
lmd_legacy->shadow_selection_override = lmd->shadow_selection_override;
|
||||
lmd_legacy->shadow_use_silhouette_override = lmd->shadow_use_silhouette_override;
|
||||
lmd_legacy->cache = lmd->cache;
|
||||
lmd_legacy->la_data_ptr = lmd->la_data_ptr;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::greasepencil::convert
|
||||
|
|
|
@ -346,9 +346,6 @@ bool BKE_paint_ensure_from_paintmode(Scene *sce, PaintMode mode)
|
|||
paint_tmp = (Paint *)&ts->imapaint;
|
||||
paint_ptr = &paint_tmp;
|
||||
break;
|
||||
case PaintMode::SculptUV:
|
||||
paint_ptr = (Paint **)&ts->uvsculpt;
|
||||
break;
|
||||
case PaintMode::GPencil:
|
||||
paint_ptr = (Paint **)&ts->gp_paint;
|
||||
break;
|
||||
|
@ -392,8 +389,6 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
|
|||
case PaintMode::Texture2D:
|
||||
case PaintMode::Texture3D:
|
||||
return &ts->imapaint.paint;
|
||||
case PaintMode::SculptUV:
|
||||
return &ts->uvsculpt->paint;
|
||||
case PaintMode::GPencil:
|
||||
return &ts->gp_paint->paint;
|
||||
case PaintMode::VertexGPencil:
|
||||
|
@ -428,8 +423,6 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(const PaintMode m
|
|||
case PaintMode::Texture2D:
|
||||
case PaintMode::Texture3D:
|
||||
return rna_enum_brush_image_tool_items;
|
||||
case PaintMode::SculptUV:
|
||||
return rna_enum_brush_uv_sculpt_tool_items;
|
||||
case PaintMode::GPencil:
|
||||
return rna_enum_brush_gpencil_types_items;
|
||||
case PaintMode::VertexGPencil:
|
||||
|
@ -460,8 +453,6 @@ const char *BKE_paint_get_tool_prop_id_from_paintmode(const PaintMode mode)
|
|||
case PaintMode::Texture2D:
|
||||
case PaintMode::Texture3D:
|
||||
return "image_tool";
|
||||
case PaintMode::SculptUV:
|
||||
return "uv_sculpt_tool";
|
||||
case PaintMode::GPencil:
|
||||
return "gpencil_tool";
|
||||
case PaintMode::VertexGPencil:
|
||||
|
@ -492,7 +483,6 @@ const char *BKE_paint_get_tool_enum_translation_context_from_paintmode(const Pai
|
|||
return BLT_I18NCONTEXT_ID_BRUSH;
|
||||
case PaintMode::Vertex:
|
||||
case PaintMode::Weight:
|
||||
case PaintMode::SculptUV:
|
||||
case PaintMode::VertexGPencil:
|
||||
case PaintMode::SculptGPencil:
|
||||
case PaintMode::WeightGPencil:
|
||||
|
@ -533,8 +523,6 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
|
|||
return &ts->gp_weightpaint->paint;
|
||||
case OB_MODE_SCULPT_CURVES:
|
||||
return &ts->curves_sculpt->paint;
|
||||
case OB_MODE_EDIT:
|
||||
return ts->uvsculpt ? &ts->uvsculpt->paint : nullptr;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -563,9 +551,6 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
|
|||
if (sima->mode == SI_MODE_PAINT) {
|
||||
return &ts->imapaint.paint;
|
||||
}
|
||||
if (sima->mode == SI_MODE_UV) {
|
||||
return &ts->uvsculpt->paint;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return &ts->imapaint.paint;
|
||||
|
@ -594,9 +579,6 @@ PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
|
|||
if (sima->mode == SI_MODE_PAINT) {
|
||||
return PaintMode::Texture2D;
|
||||
}
|
||||
if (sima->mode == SI_MODE_UV) {
|
||||
return PaintMode::SculptUV;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return PaintMode::Texture2D;
|
||||
|
@ -624,8 +606,6 @@ PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
|
|||
return PaintMode::Weight;
|
||||
case OB_MODE_TEXTURE_PAINT:
|
||||
return PaintMode::Texture3D;
|
||||
case OB_MODE_EDIT:
|
||||
return PaintMode::SculptUV;
|
||||
case OB_MODE_SCULPT_CURVES:
|
||||
return PaintMode::SculptCurves;
|
||||
default:
|
||||
|
@ -674,8 +654,6 @@ PaintMode BKE_paintmode_get_from_tool(const bToolRef *tref)
|
|||
switch (tref->mode) {
|
||||
case SI_MODE_PAINT:
|
||||
return PaintMode::Texture2D;
|
||||
case SI_MODE_UV:
|
||||
return PaintMode::SculptUV;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,10 +699,6 @@ void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint)
|
|||
paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool);
|
||||
paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
|
||||
}
|
||||
else if (ts->uvsculpt && paint == &ts->uvsculpt->paint) {
|
||||
paint->runtime.tool_offset = offsetof(Brush, uv_sculpt_tool);
|
||||
paint->runtime.ob_mode = OB_MODE_EDIT;
|
||||
}
|
||||
else if (ts->gp_paint && paint == &ts->gp_paint->paint) {
|
||||
paint->runtime.tool_offset = offsetof(Brush, gpencil_tool);
|
||||
paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL_LEGACY;
|
||||
|
@ -762,8 +736,6 @@ uint BKE_paint_get_brush_tool_offset_from_paintmode(const PaintMode mode)
|
|||
return offsetof(Brush, vertexpaint_tool);
|
||||
case PaintMode::Weight:
|
||||
return offsetof(Brush, weightpaint_tool);
|
||||
case PaintMode::SculptUV:
|
||||
return offsetof(Brush, uv_sculpt_tool);
|
||||
case PaintMode::GPencil:
|
||||
return offsetof(Brush, gpencil_tool);
|
||||
case PaintMode::VertexGPencil:
|
||||
|
@ -1104,8 +1076,6 @@ eObjectMode BKE_paint_object_mode_from_paintmode(const PaintMode mode)
|
|||
case PaintMode::Texture2D:
|
||||
case PaintMode::Texture3D:
|
||||
return OB_MODE_TEXTURE_PAINT;
|
||||
case PaintMode::SculptUV:
|
||||
return OB_MODE_EDIT;
|
||||
case PaintMode::SculptCurves:
|
||||
return OB_MODE_SCULPT_CURVES;
|
||||
case PaintMode::GPencil:
|
||||
|
@ -1140,7 +1110,6 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
|
|||
(Paint *)ts->sculpt,
|
||||
(Paint *)ts->vpaint,
|
||||
(Paint *)ts->wpaint,
|
||||
(Paint *)ts->uvsculpt,
|
||||
(Paint *)ts->curves_sculpt,
|
||||
(Paint *)&ts->imapaint));
|
||||
#ifndef NDEBUG
|
||||
|
@ -1182,10 +1151,6 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
|
|||
GpWeightPaint *data = MEM_cnew<GpWeightPaint>(__func__);
|
||||
paint = &data->paint;
|
||||
}
|
||||
else if ((UvSculpt **)r_paint == &ts->uvsculpt) {
|
||||
UvSculpt *data = MEM_cnew<UvSculpt>(__func__);
|
||||
paint = &data->paint;
|
||||
}
|
||||
else if ((CurvesSculpt **)r_paint == &ts->curves_sculpt) {
|
||||
CurvesSculpt *data = MEM_cnew<CurvesSculpt>(__func__);
|
||||
paint = &data->paint;
|
||||
|
@ -1211,17 +1176,15 @@ void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3])
|
|||
BKE_paint_ensure_from_paintmode(sce, mode);
|
||||
|
||||
/* If there's no brush, create one */
|
||||
if (PAINT_MODE_HAS_BRUSH(mode)) {
|
||||
Brush *brush = BKE_paint_brush(paint);
|
||||
if (brush == nullptr) {
|
||||
eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode);
|
||||
brush = BKE_brush_first_search(bmain, ob_mode);
|
||||
if (!brush) {
|
||||
brush = BKE_brush_add(bmain, "Brush", ob_mode);
|
||||
id_us_min(&brush->id); /* Fake user only. */
|
||||
}
|
||||
BKE_paint_brush_set(paint, brush);
|
||||
Brush *brush = BKE_paint_brush(paint);
|
||||
if (brush == nullptr) {
|
||||
eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode);
|
||||
brush = BKE_brush_first_search(bmain, ob_mode);
|
||||
if (!brush) {
|
||||
brush = BKE_brush_add(bmain, "Brush", ob_mode);
|
||||
id_us_min(&brush->id); /* Fake user only. */
|
||||
}
|
||||
BKE_paint_brush_set(paint, brush);
|
||||
}
|
||||
|
||||
copy_v3_v3_uchar(paint->paint_cursor_col, col);
|
||||
|
@ -1529,14 +1492,6 @@ void BKE_sculptsession_free(Object *ob)
|
|||
BKE_image_pool_free(ss->tex_pool);
|
||||
}
|
||||
|
||||
if (ss->pose_ik_chain_preview) {
|
||||
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
|
||||
MEM_SAFE_FREE(ss->pose_ik_chain_preview->segments[i].weights);
|
||||
}
|
||||
MEM_SAFE_FREE(ss->pose_ik_chain_preview->segments);
|
||||
MEM_SAFE_FREE(ss->pose_ik_chain_preview);
|
||||
}
|
||||
|
||||
if (ss->boundary_preview) {
|
||||
MEM_SAFE_FREE(ss->boundary_preview->verts);
|
||||
MEM_SAFE_FREE(ss->boundary_preview->edges);
|
||||
|
|
|
@ -89,9 +89,6 @@ void BKE_paint_toolslots_init_from_main(Main *bmain)
|
|||
if (ts->wpaint) {
|
||||
paint_toolslots_init_with_runtime(bmain, ts, &ts->wpaint->paint);
|
||||
}
|
||||
if (ts->uvsculpt) {
|
||||
paint_toolslots_init_with_runtime(bmain, ts, &ts->uvsculpt->paint);
|
||||
}
|
||||
if (ts->gp_paint) {
|
||||
paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_paint->paint);
|
||||
}
|
||||
|
|
|
@ -725,14 +725,6 @@ static void scene_foreach_toolsettings(LibraryForeachIDData *data,
|
|||
}
|
||||
toolsett_old->sculpt->gravity_object = gravity_object_old;
|
||||
}
|
||||
if (toolsett_old->uvsculpt) {
|
||||
paint = toolsett->uvsculpt ? &toolsett->uvsculpt->paint : nullptr;
|
||||
paint_old = &toolsett_old->uvsculpt->paint;
|
||||
BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL(
|
||||
data,
|
||||
do_undo_restore,
|
||||
scene_foreach_paint(data, paint, do_undo_restore, reader, paint_old));
|
||||
}
|
||||
if (toolsett_old->gp_paint) {
|
||||
paint = toolsett->gp_paint ? &toolsett->gp_paint->paint : nullptr;
|
||||
paint_old = &toolsett_old->gp_paint->paint;
|
||||
|
@ -1055,9 +1047,8 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
|
|||
|
||||
BKE_paint_blend_write(writer, &tos->sculpt->paint);
|
||||
}
|
||||
if (tos->uvsculpt) {
|
||||
BLO_write_struct(writer, UvSculpt, tos->uvsculpt);
|
||||
BKE_paint_blend_write(writer, &tos->uvsculpt->paint);
|
||||
if (tos->uvsculpt.strength_curve) {
|
||||
BKE_curvemapping_blend_write(writer, tos->uvsculpt.strength_curve);
|
||||
}
|
||||
if (tos->gp_paint) {
|
||||
BLO_write_struct(writer, GpPaint, tos->gp_paint);
|
||||
|
@ -1259,7 +1250,6 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->sculpt);
|
||||
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->vpaint);
|
||||
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->wpaint);
|
||||
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->uvsculpt);
|
||||
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->gp_paint);
|
||||
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->gp_vertexpaint);
|
||||
direct_link_paint_helper(reader, sce, (Paint **)&sce->toolsettings->gp_sculptpaint);
|
||||
|
@ -1272,6 +1262,11 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
sce->toolsettings->particle.scene = nullptr;
|
||||
sce->toolsettings->particle.object = nullptr;
|
||||
sce->toolsettings->gp_sculpt.paintcursor = nullptr;
|
||||
if (sce->toolsettings->uvsculpt.strength_curve) {
|
||||
BLO_read_struct(reader, CurveMapping, &sce->toolsettings->uvsculpt.strength_curve);
|
||||
BKE_curvemapping_blend_read(reader, sce->toolsettings->uvsculpt.strength_curve);
|
||||
BKE_curvemapping_init(sce->toolsettings->uvsculpt.strength_curve);
|
||||
}
|
||||
|
||||
if (sce->toolsettings->sculpt) {
|
||||
BLO_read_struct(reader, CurveMapping, &sce->toolsettings->sculpt->automasking_cavity_curve);
|
||||
|
@ -1671,9 +1666,9 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
|
|||
BKE_curvemapping_init(ts->sculpt->automasking_cavity_curve_op);
|
||||
}
|
||||
}
|
||||
if (ts->uvsculpt) {
|
||||
ts->uvsculpt = static_cast<UvSculpt *>(MEM_dupallocN(ts->uvsculpt));
|
||||
BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
|
||||
if (ts->uvsculpt.strength_curve) {
|
||||
ts->uvsculpt.strength_curve = BKE_curvemapping_copy(ts->uvsculpt.strength_curve);
|
||||
BKE_curvemapping_init(ts->uvsculpt.strength_curve);
|
||||
}
|
||||
if (ts->gp_paint) {
|
||||
ts->gp_paint = static_cast<GpPaint *>(MEM_dupallocN(ts->gp_paint));
|
||||
|
@ -1737,9 +1732,8 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
|
|||
BKE_paint_free(&toolsettings->sculpt->paint);
|
||||
MEM_freeN(toolsettings->sculpt);
|
||||
}
|
||||
if (toolsettings->uvsculpt) {
|
||||
BKE_paint_free(&toolsettings->uvsculpt->paint);
|
||||
MEM_freeN(toolsettings->uvsculpt);
|
||||
if (toolsettings->uvsculpt.strength_curve) {
|
||||
BKE_curvemapping_free(toolsettings->uvsculpt.strength_curve);
|
||||
}
|
||||
if (toolsettings->gp_paint) {
|
||||
BKE_paint_free(&toolsettings->gp_paint->paint);
|
||||
|
|
|
@ -78,10 +78,10 @@ class Task {
|
|||
other.freedata = nullptr;
|
||||
}
|
||||
|
||||
// TBB has a check in tbb/include/task_group.h where __TBB_CPP11_RVALUE_REF_PRESENT should evaluate
|
||||
// to true as with the other MSVC build. However, because of the clang compiler it does not and we
|
||||
// attempt to call a deleted constructor in the tbb_task_pool_run function. This check fixes this
|
||||
// issue and keeps our Task constructor valid
|
||||
/* TBB has a check in `tbb/include/task_group.h` where `__TBB_CPP11_RVALUE_REF_PRESENT` should
|
||||
* evaluate to true as with the other MSVC build. However, because of the clang compiler
|
||||
* it does not and we attempt to call a deleted constructor in the tbb_task_pool_run function.
|
||||
* This check fixes this issue and keeps our Task constructor valid. */
|
||||
#if (defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10) || \
|
||||
(defined(_MSC_VER) && defined(__clang__) && TBB_INTERFACE_VERSION_MAJOR < 12)
|
||||
Task(const Task &other)
|
||||
|
|
|
@ -797,9 +797,6 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa
|
|||
if (ts->sculpt) {
|
||||
callback(ts->sculpt->paint.cavity_curve);
|
||||
}
|
||||
if (ts->uvsculpt) {
|
||||
callback(ts->uvsculpt->paint.cavity_curve);
|
||||
}
|
||||
if (ts->gp_paint) {
|
||||
callback(ts->gp_paint->paint.cavity_curve);
|
||||
}
|
||||
|
|
|
@ -3491,12 +3491,6 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 302, 6)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
if (ts->uv_relax_method == 0) {
|
||||
ts->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
|
||||
}
|
||||
}
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *tool_settings = scene->toolsettings;
|
||||
tool_settings->snap_flag_seq = tool_settings->snap_flag &
|
||||
|
|
|
@ -1963,13 +1963,6 @@ static void versioning_nodes_dynamic_sockets_2(bNodeTree &ntree)
|
|||
static void versioning_grease_pencil_stroke_radii_scaling(GreasePencil *grease_pencil)
|
||||
{
|
||||
using namespace blender;
|
||||
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px` was
|
||||
* the brush size which would be stored in the stroke thickness and then scaled by the point
|
||||
* pressure factor. Finally, the render engine would divide this thickness value by 2000 (we're
|
||||
* going from a thickness to a radius, hence the factor of two) to convert back into blender
|
||||
* units.
|
||||
* Store the radius now directly in blender units. This makes it consistent with how hair curves
|
||||
* handle the radius. */
|
||||
for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
|
||||
if (base->type != GP_DRAWING) {
|
||||
continue;
|
||||
|
@ -1978,7 +1971,7 @@ static void versioning_grease_pencil_stroke_radii_scaling(GreasePencil *grease_p
|
|||
MutableSpan<float> radii = drawing.radii_for_write();
|
||||
threading::parallel_for(radii.index_range(), 8192, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
radii[i] /= 2000.0f;
|
||||
radii[i] *= bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -2953,9 +2946,6 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
input_sample_values[2] = ts->curves_sculpt != nullptr ?
|
||||
ts->curves_sculpt->paint.num_input_samples_deprecated :
|
||||
1;
|
||||
input_sample_values[3] = ts->uvsculpt != nullptr ?
|
||||
ts->uvsculpt->paint.num_input_samples_deprecated :
|
||||
1;
|
||||
|
||||
input_sample_values[4] = ts->gp_paint != nullptr ?
|
||||
ts->gp_paint->paint.num_input_samples_deprecated :
|
||||
|
@ -3129,7 +3119,7 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 8)) {
|
||||
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
|
||||
light->shadow_filter_radius = 3.0f;
|
||||
light->shadow_filter_radius = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3234,6 +3224,18 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 23)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
if (!ts->uvsculpt.strength_curve) {
|
||||
ts->uvsculpt.size = 50;
|
||||
ts->uvsculpt.strength = 1.0f;
|
||||
ts->uvsculpt.curve_preset = BRUSH_CURVE_SMOOTH;
|
||||
ts->uvsculpt.strength_curve = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
@ -303,7 +303,8 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm,
|
|||
delimit_data.cd_loop_type = CD_PROP_FLOAT2;
|
||||
delimit_data.cd_loop_size = CustomData_sizeof(eCustomDataType(delimit_data.cd_loop_type));
|
||||
delimit_data.cd_loop_offset = CustomData_get_n_offset(&bm->ldata, CD_PROP_FLOAT2, 0);
|
||||
delimit_data.cd_loop_offset_end = delimit_data.cd_loop_size * layer_len;
|
||||
delimit_data.cd_loop_offset_end = delimit_data.cd_loop_offset +
|
||||
delimit_data.cd_loop_size * layer_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,15 +59,17 @@ void Light::sync(ShadowModule &shadows, const Object *ob, float threshold)
|
|||
this->color = float3(&la->r) * la->energy;
|
||||
|
||||
float3 scale;
|
||||
this->object_mat = ob->object_to_world();
|
||||
this->object_mat.view<3, 3>() = normalize_and_get_size(this->object_mat.view<3, 3>(), scale);
|
||||
float4x4 object_to_world = ob->object_to_world();
|
||||
object_to_world.view<3, 3>() = normalize_and_get_size(object_to_world.view<3, 3>(), scale);
|
||||
|
||||
/* Make sure we have consistent handedness (in case of negatively scaled Z axis). */
|
||||
float3 back = cross(float3(this->_right), float3(this->_up));
|
||||
if (dot(back, float3(this->_back)) < 0.0f) {
|
||||
negate_v3(this->_up);
|
||||
float3 back = cross(float3(object_to_world.x_axis()), float3(object_to_world.y_axis()));
|
||||
if (dot(back, float3(object_to_world.z_axis())) < 0.0f) {
|
||||
negate_v3(object_to_world.y_axis());
|
||||
}
|
||||
|
||||
this->object_to_world = object_to_world;
|
||||
|
||||
shape_parameters_set(la, scale, threshold);
|
||||
|
||||
const bool diffuse_visibility = (ob->visibility_flag & OB_HIDE_DIFFUSE) == 0;
|
||||
|
@ -93,7 +95,7 @@ void Light::sync(ShadowModule &shadows, const Object *ob, float threshold)
|
|||
if (la->mode & LA_SHADOW) {
|
||||
shadow_ensure(shadows);
|
||||
if (is_sun_light(this->type)) {
|
||||
this->directional->sync(this->object_mat,
|
||||
this->directional->sync(object_to_world,
|
||||
1.0f,
|
||||
la->sun_angle * la->shadow_softness_factor,
|
||||
la->shadow_trace_distance);
|
||||
|
@ -113,7 +115,7 @@ void Light::sync(ShadowModule &shadows, const Object *ob, float threshold)
|
|||
shadow_radius = la->shadow_softness_factor * la->radius;
|
||||
}
|
||||
this->punctual->sync(this->type,
|
||||
this->object_mat,
|
||||
object_to_world,
|
||||
la->spotsize,
|
||||
radius,
|
||||
this->local.influence_radius_max,
|
||||
|
@ -293,7 +295,9 @@ float Light::point_radiance_get()
|
|||
void Light::debug_draw()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
drw_debug_sphere(float3(_position), local.influence_radius_max, float4(0.8f, 0.3f, 0.0f, 1.0f));
|
||||
drw_debug_sphere(transform_location(this->object_to_world),
|
||||
local.influence_radius_max,
|
||||
float4(0.8f, 0.3f, 0.0f, 1.0f));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,80 @@ constexpr GPUSamplerState with_filter = {GPU_SAMPLER_FILTERING_LINEAR};
|
|||
|
||||
#define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform
|
||||
* \{ */
|
||||
|
||||
struct Transform {
|
||||
/* The transform is stored transposed for compactness. */
|
||||
float4 x, y, z;
|
||||
#if IS_CPP
|
||||
Transform() = default;
|
||||
Transform(const float4x4 &tx)
|
||||
: x(tx[0][0], tx[1][0], tx[2][0], tx[3][0]),
|
||||
y(tx[0][1], tx[1][1], tx[2][1], tx[3][1]),
|
||||
z(tx[0][2], tx[1][2], tx[2][2], tx[3][2])
|
||||
{
|
||||
}
|
||||
|
||||
operator float4x4() const
|
||||
{
|
||||
return float4x4(float4(x.x, y.x, z.x, 0.0f),
|
||||
float4(x.y, y.y, z.y, 0.0f),
|
||||
float4(x.z, y.z, z.z, 0.0f),
|
||||
float4(x.w, y.w, z.w, 1.0f));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline float3 transform_x_axis(Transform t)
|
||||
{
|
||||
return float3(t.x.x, t.y.x, t.z.x);
|
||||
}
|
||||
static inline float3 transform_y_axis(Transform t)
|
||||
{
|
||||
return float3(t.x.y, t.y.y, t.z.y);
|
||||
}
|
||||
static inline float3 transform_z_axis(Transform t)
|
||||
{
|
||||
return float3(t.x.z, t.y.z, t.z.z);
|
||||
}
|
||||
static inline float3 transform_location(Transform t)
|
||||
{
|
||||
return float3(t.x.w, t.y.w, t.z.w);
|
||||
}
|
||||
|
||||
static inline float3 transform_point(Transform t, float3 point)
|
||||
{
|
||||
return float4(point, 1.0f) * float3x4(t.x, t.y, t.z);
|
||||
}
|
||||
|
||||
static inline float3 transform_direction(Transform t, float3 direction)
|
||||
{
|
||||
return direction * float3x3(float3(t.x.x, t.x.y, t.x.z),
|
||||
float3(t.y.x, t.y.y, t.y.z),
|
||||
float3(t.z.x, t.z.y, t.z.z));
|
||||
}
|
||||
|
||||
static inline float3 transform_direction_transposed(Transform t, float3 direction)
|
||||
{
|
||||
return float3x3(float3(t.x.x, t.x.y, t.x.z),
|
||||
float3(t.y.x, t.y.y, t.y.z),
|
||||
float3(t.z.x, t.z.y, t.z.z)) *
|
||||
direction;
|
||||
}
|
||||
|
||||
/* Assumes the transform has unit scale. */
|
||||
static inline float3 transform_point_inversed(Transform t, float3 point)
|
||||
{
|
||||
return float3x3(float3(t.x.x, t.x.y, t.x.z),
|
||||
float3(t.y.x, t.y.y, t.y.z),
|
||||
float3(t.z.x, t.z.y, t.z.z)) *
|
||||
(point - transform_location(t));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Debug Mode
|
||||
* \{ */
|
||||
|
@ -870,21 +944,8 @@ BLI_STATIC_ASSERT(sizeof(LightSunData) == sizeof(LightLocalData), "Data size mus
|
|||
#endif
|
||||
|
||||
struct LightData {
|
||||
/** Normalized object to world matrix. */
|
||||
/* TODO(fclem): Use float4x3. */
|
||||
float4x4 object_mat;
|
||||
/** Aliases for axes. */
|
||||
#ifndef USE_GPU_SHADER_CREATE_INFO
|
||||
# define _right object_mat[0]
|
||||
# define _up object_mat[1]
|
||||
# define _back object_mat[2]
|
||||
# define _position object_mat[3]
|
||||
#else
|
||||
# define _right object_mat[0].xyz
|
||||
# define _up object_mat[1].xyz
|
||||
# define _back object_mat[2].xyz
|
||||
# define _position object_mat[3].xyz
|
||||
#endif
|
||||
/** Normalized object to world matrix. Stored transposed for compactness. */
|
||||
Transform object_to_world;
|
||||
|
||||
/** Power depending on shader type. Referenced by LightingType. */
|
||||
float4 power;
|
||||
|
@ -922,6 +983,23 @@ struct LightData {
|
|||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(LightData, 16)
|
||||
|
||||
static inline float3 light_x_axis(LightData light)
|
||||
{
|
||||
return transform_x_axis(light.object_to_world);
|
||||
}
|
||||
static inline float3 light_y_axis(LightData light)
|
||||
{
|
||||
return transform_y_axis(light.object_to_world);
|
||||
}
|
||||
static inline float3 light_z_axis(LightData light)
|
||||
{
|
||||
return transform_z_axis(light.object_to_world);
|
||||
}
|
||||
static inline float3 light_position_get(LightData light)
|
||||
{
|
||||
return transform_location(light.object_to_world);
|
||||
}
|
||||
|
||||
#ifdef GPU_SHADER
|
||||
# define CHECK_TYPE_PAIR(a, b)
|
||||
# define CHECK_TYPE(a, b)
|
||||
|
|
|
@ -370,11 +370,7 @@ void ShadowPunctual::end_sync(Light &light, float lod_bias)
|
|||
compute_projection_boundaries(
|
||||
light.type, light_radius_, shadow_radius_, max_distance_, near, far, side, shift);
|
||||
|
||||
float4x4 obmat_tmp = light.object_mat;
|
||||
|
||||
/* Clear embedded custom data. */
|
||||
obmat_tmp[0][3] = obmat_tmp[1][3] = obmat_tmp[2][3] = 0.0f;
|
||||
obmat_tmp[3][3] = 1.0f;
|
||||
float4x4 obmat_tmp = light.object_to_world;
|
||||
|
||||
/* Acquire missing tile-maps. */
|
||||
while (tilemaps_.size() < tilemaps_needed_) {
|
||||
|
@ -519,7 +515,9 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
|
|||
float2 farthest_tilemap_center = local_view_direction * half_size * (levels_range.size() - 1);
|
||||
|
||||
/* Offset for smooth level transitions. */
|
||||
light.object_mat.location() = near_point;
|
||||
light.object_to_world.x.w = near_point.x;
|
||||
light.object_to_world.y.w = near_point.y;
|
||||
light.object_to_world.z.w = near_point.z;
|
||||
|
||||
/* Offset in tiles from the scene origin to the center of the first tile-maps. */
|
||||
int2 origin_offset = int2(round(float2(near_point) / tile_size));
|
||||
|
@ -637,7 +635,10 @@ void ShadowDirectional::clipmap_tilemaps_distribution(Light &light,
|
|||
light.type = LIGHT_SUN;
|
||||
|
||||
/* Used for selecting the clipmap level. */
|
||||
light.object_mat.location() = camera.position() * float3x3(object_mat_.view<3, 3>());
|
||||
float3 location = camera.position() * float3x3(object_mat_.view<3, 3>());
|
||||
light.object_to_world.x.w = location.x;
|
||||
light.object_to_world.y.w = location.y;
|
||||
light.object_to_world.z.w = location.z;
|
||||
/* Used as origin for the clipmap_base_offset trick. */
|
||||
light.sun.clipmap_origin = float2(level_offset_max * tile_size_max);
|
||||
|
||||
|
|
|
@ -117,10 +117,8 @@ void SyncModule::sync_mesh(Object *ob,
|
|||
return;
|
||||
}
|
||||
|
||||
if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) {
|
||||
/** NOTE:
|
||||
* EEVEE doesn't render meshes with bounds or wire display type in the viewport,
|
||||
* but Cycles does. */
|
||||
if ((ob->dt < OB_SOLID) && ((inst_.is_viewport() && inst_.v3d->shading.type != OB_RENDER))) {
|
||||
/** Do not render objects with display type lower than solid when in material preview mode. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,11 +38,14 @@ void main()
|
|||
LightSpotData spot = light_spot_data_get(light);
|
||||
/* Only for < ~170 degree Cone due to plane extraction precision. */
|
||||
if (spot.spot_tan < 10.0) {
|
||||
vec3 x_axis = light_x_axis(light);
|
||||
vec3 y_axis = light_y_axis(light);
|
||||
vec3 z_axis = light_z_axis(light);
|
||||
Pyramid pyramid = shape_pyramid_non_oblique(
|
||||
light._position,
|
||||
light._position - light._back * spot.influence_radius_max,
|
||||
light._right * spot.influence_radius_max * spot.spot_tan / spot.spot_size_inv.x,
|
||||
light._up * spot.influence_radius_max * spot.spot_tan / spot.spot_size_inv.y);
|
||||
light_position_get(light),
|
||||
light_position_get(light) - z_axis * spot.influence_radius_max,
|
||||
x_axis * spot.influence_radius_max * spot.spot_tan / spot.spot_size_inv.x,
|
||||
y_axis * spot.influence_radius_max * spot.spot_tan / spot.spot_size_inv.y);
|
||||
if (!intersect_view(pyramid)) {
|
||||
return;
|
||||
}
|
||||
|
@ -52,7 +55,7 @@ void main()
|
|||
case LIGHT_ELLIPSE:
|
||||
case LIGHT_OMNI_SPHERE:
|
||||
case LIGHT_OMNI_DISK:
|
||||
sphere.center = light._position;
|
||||
sphere.center = light_position_get(light);
|
||||
sphere.radius = light_local_data_get(light).influence_radius_max;
|
||||
break;
|
||||
default:
|
||||
|
@ -66,7 +69,7 @@ void main()
|
|||
if (intersect_view(sphere)) {
|
||||
uint index = atomicAdd(light_cull_buf.visible_count, 1u);
|
||||
|
||||
float z_dist = dot(drw_view_forward(), light._position) -
|
||||
float z_dist = dot(drw_view_forward(), light_position_get(light)) -
|
||||
dot(drw_view_forward(), drw_view_position());
|
||||
out_zdist_buf[index] = z_dist;
|
||||
out_key_buf[index] = l_idx;
|
||||
|
|
|
@ -148,10 +148,10 @@ void main()
|
|||
LightData light = light_buf[l_idx];
|
||||
|
||||
/* Culling in view space for precision and simplicity. */
|
||||
vec3 vP = drw_point_world_to_view(light._position);
|
||||
vec3 v_right = drw_normal_world_to_view(light._right);
|
||||
vec3 v_up = drw_normal_world_to_view(light._up);
|
||||
vec3 v_back = drw_normal_world_to_view(light._back);
|
||||
vec3 vP = drw_point_world_to_view(light_position_get(light));
|
||||
vec3 v_right = drw_normal_world_to_view(light_x_axis(light));
|
||||
vec3 v_up = drw_normal_world_to_view(light_y_axis(light));
|
||||
vec3 v_back = drw_normal_world_to_view(light_z_axis(light));
|
||||
float radius = light_local_data_get(light).influence_radius_max;
|
||||
|
||||
Sphere sphere = shape_sphere(vP, radius);
|
||||
|
|
|
@ -36,7 +36,7 @@ void main()
|
|||
continue;
|
||||
}
|
||||
LightData light = light_buf[index];
|
||||
vec3 P = light._position;
|
||||
vec3 P = light_position_get(light);
|
||||
/* TODO(fclem): Could have better bounds for spot and area lights. */
|
||||
float radius = light_local_data_get(light).influence_radius_max;
|
||||
float z_dist = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
|
||||
|
|
|
@ -24,11 +24,11 @@ LightVector light_vector_get(LightData light, const bool is_directional, vec3 P)
|
|||
{
|
||||
LightVector lv;
|
||||
if (is_directional) {
|
||||
lv.L = light._back;
|
||||
lv.L = light_z_axis(light);
|
||||
lv.dist = 1.0;
|
||||
}
|
||||
else {
|
||||
lv.L = light._position - P;
|
||||
lv.L = light_position_get(light) - P;
|
||||
float inv_distance = inversesqrt(length_squared(lv.L));
|
||||
lv.L *= inv_distance;
|
||||
lv.dist = 1.0 / inv_distance;
|
||||
|
@ -42,21 +42,17 @@ LightVector light_shape_vector_get(LightData light, const bool is_directional, v
|
|||
if (!is_directional && is_area_light(light.type)) {
|
||||
LightAreaData area = light_area_data_get(light);
|
||||
|
||||
vec3 L = P - light._position;
|
||||
vec2 closest_point = vec2(dot(light._right, L), dot(light._up, L));
|
||||
closest_point /= area.size;
|
||||
|
||||
vec3 lP = transform_point_inversed(light.object_to_world, P);
|
||||
vec2 ls_closest_point = lP.xy;
|
||||
if (light.type == LIGHT_ELLIPSE) {
|
||||
closest_point /= max(1.0, length(closest_point));
|
||||
ls_closest_point /= max(1.0, length(ls_closest_point / area.size));
|
||||
}
|
||||
else {
|
||||
closest_point = clamp(closest_point, -1.0, 1.0);
|
||||
ls_closest_point = clamp(ls_closest_point, -area.size, area.size);
|
||||
}
|
||||
closest_point *= area.size;
|
||||
vec3 ws_closest_point = transform_point(light.object_to_world, vec3(ls_closest_point, 0.0));
|
||||
|
||||
vec3 L_prime = light._right * closest_point.x + light._up * closest_point.y;
|
||||
|
||||
L = L_prime - L;
|
||||
vec3 L = ws_closest_point - P;
|
||||
float inv_distance = inversesqrt(length_squared(L));
|
||||
LightVector lv;
|
||||
lv.L = L * inv_distance;
|
||||
|
@ -70,19 +66,7 @@ LightVector light_shape_vector_get(LightData light, const bool is_directional, v
|
|||
/* Rotate vector to light's local space. Does not translate. */
|
||||
vec3 light_world_to_local(LightData light, vec3 L)
|
||||
{
|
||||
/* Avoid relying on compiler to optimize this.
|
||||
* vec3 lL = transpose(mat3(light.object_mat)) * L; */
|
||||
vec3 lL;
|
||||
lL.x = dot(light.object_mat[0].xyz, L);
|
||||
lL.y = dot(light.object_mat[1].xyz, L);
|
||||
lL.z = dot(light.object_mat[2].xyz, L);
|
||||
return lL;
|
||||
}
|
||||
|
||||
/* Transform position from light's local space to world space. Does translation. */
|
||||
vec3 light_local_position_to_world(LightData light, vec3 lP)
|
||||
{
|
||||
return mat3(light.object_mat) * lP + light._position;
|
||||
return transform_direction_transposed(light.object_to_world, L);
|
||||
}
|
||||
|
||||
/* From Frostbite PBR Course
|
||||
|
@ -101,7 +85,7 @@ float light_spot_attenuation(LightData light, vec3 L)
|
|||
vec3 lL = light_world_to_local(light, L);
|
||||
float ellipse = inversesqrt(1.0 + length_squared(lL.xy * spot.spot_size_inv / lL.z));
|
||||
float spotmask = smoothstep(0.0, 1.0, ellipse * spot.spot_mul + spot.spot_bias);
|
||||
return spotmask * step(0.0, -dot(L, -light._back));
|
||||
return (lL.z > 0.0) ? spotmask : 0.0;
|
||||
}
|
||||
|
||||
float light_attenuation_common(LightData light, const bool is_directional, vec3 L)
|
||||
|
@ -113,7 +97,7 @@ float light_attenuation_common(LightData light, const bool is_directional, vec3
|
|||
return light_spot_attenuation(light, L);
|
||||
}
|
||||
if (is_area_light(light.type)) {
|
||||
return step(0.0, -dot(L, -light._back));
|
||||
return float(dot(L, light_z_axis(light)) > 0.0);
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
@ -202,7 +186,7 @@ float light_point_light(LightData light, const bool is_directional, LightVector
|
|||
|
||||
if (is_area_light(light.type)) {
|
||||
/* Modulate by light plane orientation / solid angle. */
|
||||
power *= saturate(dot(light._back, lv.L));
|
||||
power *= saturate(dot(light_z_axis(light), lv.L));
|
||||
}
|
||||
return power;
|
||||
}
|
||||
|
@ -227,12 +211,15 @@ float light_ltc(
|
|||
return 1.0;
|
||||
}
|
||||
|
||||
vec3 Px = light_x_axis(light);
|
||||
vec3 Py = light_y_axis(light);
|
||||
|
||||
if (light.type == LIGHT_RECT) {
|
||||
LightAreaData area = light_area_data_get(light);
|
||||
|
||||
vec3 corners[4];
|
||||
corners[0] = light._right * area.size.x + light._up * -area.size.y;
|
||||
corners[1] = light._right * area.size.x + light._up * area.size.y;
|
||||
corners[0] = Px * area.size.x + Py * -area.size.y;
|
||||
corners[1] = Px * area.size.x + Py * area.size.y;
|
||||
corners[2] = -corners[0];
|
||||
corners[3] = -corners[1];
|
||||
|
||||
|
@ -247,9 +234,6 @@ float light_ltc(
|
|||
return ltc_evaluate_quad(utility_tx, corners, vec3(0.0, 0.0, 1.0));
|
||||
}
|
||||
else {
|
||||
vec3 Px = light._right;
|
||||
vec3 Py = light._up;
|
||||
|
||||
if (!is_area_light(light.type)) {
|
||||
make_orthonormal_basis(lv.L, Px, Py);
|
||||
}
|
||||
|
|
|
@ -124,11 +124,6 @@ bool debug_tilemaps(vec3 P, LightData light)
|
|||
out_color_add = vec4(debug_tile_state_color(light.type, tile), 0.0);
|
||||
out_color_mul = vec4(0.0);
|
||||
|
||||
# ifdef DRW_DEBUG_PRINT
|
||||
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
|
||||
drw_print(light.object_mat);
|
||||
}
|
||||
# endif
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
@ -144,11 +139,6 @@ bool debug_tilemaps(vec3 P, LightData light)
|
|||
out_color_add = vec4(debug_tile_state_color(tile), 0.0);
|
||||
out_color_mul = vec4(0.0);
|
||||
|
||||
# ifdef DRW_DEBUG_PRINT
|
||||
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
|
||||
drw_print(light.object_mat);
|
||||
}
|
||||
# endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -186,7 +176,7 @@ void debug_random_tilemap_color(vec3 P, LightData light)
|
|||
coord = shadow_directional_coordinates(light, lP);
|
||||
}
|
||||
else {
|
||||
vec3 lP = light_world_to_local(light, P - light._position);
|
||||
vec3 lP = light_world_to_local(light, P - light_position_get(light));
|
||||
int face_id = shadow_punctual_face_index_get(lP);
|
||||
lP = shadow_punctual_local_position_to_face_local(face_id, lP);
|
||||
coord = shadow_punctual_coordinates(light, lP, face_id);
|
||||
|
|
|
@ -152,12 +152,12 @@ vec3 shadow_punctual_reconstruct_position(ShadowSampleParams params,
|
|||
vec3 lP = project_point(wininv, clip_P);
|
||||
int face_id = params.tilemap_index - light.tilemap_index;
|
||||
lP = shadow_punctual_face_local_to_local_position(face_id, lP);
|
||||
return mat3(light.object_mat) * lP + light._position;
|
||||
return transform_point(light.object_to_world, lP);
|
||||
}
|
||||
|
||||
ShadowSampleParams shadow_punctual_sample_params_get(LightData light, vec3 P)
|
||||
{
|
||||
vec3 lP = (P - light._position) * mat3(light.object_mat);
|
||||
vec3 lP = transform_point_inversed(light.object_to_world, P);
|
||||
|
||||
int face_id = shadow_punctual_face_index_get(lP);
|
||||
/* Local Light Space > Face Local (View) Space. */
|
||||
|
@ -205,7 +205,7 @@ ShadowDirectionalSampleInfo shadow_directional_sample_info_get(LightData light,
|
|||
info.clip_near = orderedIntBitsToFloat(light.clip_near);
|
||||
info.clip_far = orderedIntBitsToFloat(light.clip_far);
|
||||
|
||||
int level = shadow_directional_level(light, lP - light._position);
|
||||
int level = shadow_directional_level(light, lP - light_position_get(light));
|
||||
/* This difference needs to be less than 32 for the later shift to be valid.
|
||||
* This is ensured by ShadowDirectional::clipmap_level_range(). */
|
||||
info.level_relative = level - light_sun_data_get(light).clipmap_lod_min;
|
||||
|
@ -234,14 +234,14 @@ vec3 shadow_directional_reconstruct_position(ShadowSampleParams params, LightDat
|
|||
lP.xy = clipmap_pos + info.clipmap_origin;
|
||||
lP.z = (params.uv.z + info.clip_near) * -1.0;
|
||||
|
||||
return mat3(light.object_mat) * lP;
|
||||
return transform_direction_transposed(light.object_to_world, lP);
|
||||
}
|
||||
|
||||
ShadowSampleParams shadow_directional_sample_params_get(usampler2D tilemaps_tx,
|
||||
LightData light,
|
||||
vec3 P)
|
||||
{
|
||||
vec3 lP = P * mat3(light.object_mat);
|
||||
vec3 lP = transform_direction(light.object_to_world, P);
|
||||
ShadowDirectionalSampleInfo info = shadow_directional_sample_info_get(light, lP);
|
||||
|
||||
ShadowCoordinates coord = shadow_directional_coordinates(light, lP);
|
||||
|
|
|
@ -55,15 +55,15 @@ void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radi
|
|||
|
||||
/* TODO(Miguel Pozo): Implement lod_bias support. */
|
||||
if (radius == 0.0) {
|
||||
int level = shadow_directional_level(light, lP - light._position);
|
||||
int level = shadow_directional_level(light, lP - light_position_get(light));
|
||||
ShadowCoordinates coord = shadow_directional_coordinates_at_level(light, lP, level);
|
||||
shadow_tag_usage_tile(light, coord.tile_coord, 0, coord.tilemap_index);
|
||||
}
|
||||
else {
|
||||
vec3 start_lP = light_world_to_local(light, P - V * radius);
|
||||
vec3 end_lP = light_world_to_local(light, P + V * radius);
|
||||
int min_level = shadow_directional_level(light, start_lP - light._position);
|
||||
int max_level = shadow_directional_level(light, end_lP - light._position);
|
||||
int min_level = shadow_directional_level(light, start_lP - light_position_get(light));
|
||||
int max_level = shadow_directional_level(light, end_lP - light_position_get(light));
|
||||
|
||||
for (int level = min_level; level <= max_level; level++) {
|
||||
ShadowCoordinates coord_min = shadow_directional_coordinates_at_level(
|
||||
|
@ -89,7 +89,7 @@ void shadow_tag_usage_tilemap_punctual(
|
|||
return;
|
||||
}
|
||||
|
||||
vec3 lP = light_world_to_local(light, P - light._position);
|
||||
vec3 lP = light_world_to_local(light, P - light_position_get(light));
|
||||
float dist_to_light = max(length(lP) - radius, 1e-5);
|
||||
if (dist_to_light > light_local_data_get(light).influence_radius_max) {
|
||||
return;
|
||||
|
|
|
@ -111,7 +111,9 @@ void main()
|
|||
set_clipmap_data(light, 0, 2, 0.0, 0.0);
|
||||
|
||||
light.tilemap_index = light_sun_data_get(light).clipmap_lod_min;
|
||||
light._position = vec3(0.0);
|
||||
light.object_to_world.x = float4(1.0, 0.0, 0.0, 0.0);
|
||||
light.object_to_world.y = float4(0.0, 1.0, 0.0, 0.0);
|
||||
light.object_to_world.z = float4(0.0, 0.0, 1.0, 0.0);
|
||||
light.lod_bias = 0;
|
||||
|
||||
float lod_min_tile_size = exp2(float(light_sun_data_get(light).clipmap_lod_min)) /
|
||||
|
@ -226,7 +228,9 @@ void main()
|
|||
// clipmap_lod_max = 2; /* 3 tile-maps. */
|
||||
set_clipmap_data(light, 0, 2, 0.0, 0.0);
|
||||
light.tilemap_index = 1;
|
||||
light._position = vec3(0.0);
|
||||
light.object_to_world.x = float4(1.0, 0.0, 0.0, 0.0);
|
||||
light.object_to_world.y = float4(0.0, 1.0, 0.0, 0.0);
|
||||
light.object_to_world.z = float4(0.0, 0.0, 1.0, 0.0);
|
||||
light.lod_bias = light_sun_data_get(light).clipmap_lod_min - 1;
|
||||
float lod_tile_size = exp2(float(light_sun_data_get(light).clipmap_lod_min)) /
|
||||
float(SHADOW_TILEMAP_RES);
|
||||
|
|
|
@ -53,7 +53,7 @@ void main()
|
|||
float local_min = FLT_MAX;
|
||||
float local_max = -FLT_MAX;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float z = dot(box.corners[i].xyz, -light._back);
|
||||
float z = dot(box.corners[i].xyz, -light_z_axis(light));
|
||||
local_min = min(local_min, z);
|
||||
local_max = max(local_max, z);
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ ShadowSamplingTile shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int t
|
|||
* This function should be the inverse of ShadowDirectional::coverage_get().
|
||||
*
|
||||
* \a lP shading point position in light space, relative to the to camera position snapped to
|
||||
* the smallest clip-map level (`shadow_world_to_local(light, P) - light._position`).
|
||||
* the smallest clip-map level (`shadow_world_to_local(light, P) - light_position_get(light)`).
|
||||
*/
|
||||
|
||||
float shadow_directional_level_fractional(LightData light, vec3 lP)
|
||||
|
@ -149,7 +149,7 @@ float shadow_punctual_footprint_ratio(LightData light,
|
|||
* This gives a good approximation of what LOD to select to get a somewhat uniform shadow map
|
||||
* resolution in screen space. */
|
||||
|
||||
float dist_to_light = distance(P, light._position);
|
||||
float dist_to_light = distance(P, light_position_get(light));
|
||||
float footprint_ratio = dist_to_light;
|
||||
/* Project the radius to the screen. 1 unit away from the camera the same way
|
||||
* pixel_world_radius_inv was computed. Not needed in orthographic mode. */
|
||||
|
@ -225,7 +225,7 @@ ShadowCoordinates shadow_directional_coordinates_at_level(LightData light, vec3
|
|||
*/
|
||||
ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP)
|
||||
{
|
||||
int level = shadow_directional_level(light, lP - light._position);
|
||||
int level = shadow_directional_level(light, lP - light_position_get(light));
|
||||
return shadow_directional_coordinates_at_level(light, lP, level);
|
||||
}
|
||||
|
||||
|
|
|
@ -247,7 +247,7 @@ ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state,
|
|||
/* Ray position is ray local position with origin at light origin. */
|
||||
vec4 ray_pos = ray.origin + ray.direction * state.ray_time;
|
||||
|
||||
int level = shadow_directional_level(ray.light, ray_pos.xyz - ray.light._position);
|
||||
int level = shadow_directional_level(ray.light, ray_pos.xyz - light_position_get(ray.light));
|
||||
/* This difference needs to be less than 32 for the later shift to be valid.
|
||||
* This is ensured by ShadowDirectional::clipmap_level_range(). */
|
||||
int level_relative = level - light_sun_data_get(ray.light).clipmap_lod_min;
|
||||
|
@ -460,7 +460,7 @@ vec3 shadow_pcf_offset(LightData light, const bool is_directional, vec3 P, vec3
|
|||
/* Scale the offset based on shadow LOD. */
|
||||
if (is_directional) {
|
||||
vec3 lP = light_world_to_local(light, P);
|
||||
float level = shadow_directional_level_fractional(light, lP - light._position);
|
||||
float level = shadow_directional_level_fractional(light, lP - light_position_get(light));
|
||||
float pcf_scale = mix(0.5, 1.0, fract(level));
|
||||
pcf_offset *= pcf_scale;
|
||||
}
|
||||
|
@ -550,7 +550,7 @@ ShadowEvalResult shadow_eval(LightData light,
|
|||
P += N_bias * normal_offset;
|
||||
|
||||
vec3 lP = is_directional ? light_world_to_local(light, P) :
|
||||
light_world_to_local(light, P - light._position);
|
||||
light_world_to_local(light, P - light_position_get(light));
|
||||
vec3 lNg = light_world_to_local(light, Ng);
|
||||
/* Invert horizon clipping. */
|
||||
lNg = (is_transmission) ? -lNg : lNg;
|
||||
|
|
|
@ -26,10 +26,20 @@ void main()
|
|||
{
|
||||
float f_depth = gl_FragCoord.z + fwidth(gl_FragCoord.z);
|
||||
|
||||
#ifdef SHADOW_UPDATE_TBDR
|
||||
/* We need to write to gl_FragDepth un-conditionnally. So we cannot early exit or use discard. */
|
||||
# define discard_result f_depth = 1.0;
|
||||
#else
|
||||
# define discard_result \
|
||||
discard; \
|
||||
return;
|
||||
#endif
|
||||
/* Avoid values greater than 1. */
|
||||
f_depth = saturate(f_depth);
|
||||
|
||||
/* Clip to light shape. */
|
||||
if (length_squared(shadow_clip.vector) < 1.0) {
|
||||
discard;
|
||||
return;
|
||||
discard_result;
|
||||
}
|
||||
|
||||
#ifdef MAT_TRANSPARENT
|
||||
|
@ -42,8 +52,7 @@ void main()
|
|||
|
||||
float transparency = average(g_transmittance);
|
||||
if (transparency > random_threshold) {
|
||||
discard;
|
||||
return;
|
||||
discard_result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -78,8 +87,7 @@ void main()
|
|||
#endif
|
||||
|
||||
#ifdef SHADOW_UPDATE_TBDR
|
||||
/* Store output depth in tile memory using F32 attachment. NOTE: As depth testing is enabled,
|
||||
* only the closest fragment will store the result. */
|
||||
gl_FragDepth = f_depth;
|
||||
out_depth = f_depth;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ vec3 volume_light(LightData light, const bool is_directional, LightVector lv)
|
|||
|
||||
if (light.type == LIGHT_RECT || light.type == LIGHT_ELLIPSE) {
|
||||
/* Modulate by light plane orientation / solid angle. */
|
||||
power *= saturate(dot(light._back, lv.L));
|
||||
power *= saturate(dot(light_z_axis(light), lv.L));
|
||||
}
|
||||
}
|
||||
return light.color * light.power[LIGHT_VOLUME] * power;
|
||||
|
|
|
@ -250,9 +250,6 @@ GPU_SHADER_CREATE_INFO(eevee_surf_shadow_atomic)
|
|||
.additional_info("eevee_surf_shadow")
|
||||
.define("SHADOW_UPDATE_ATOMIC_RASTER")
|
||||
.builtins(BuiltinBits::TEXTURE_ATOMIC)
|
||||
/* Early fragment test for speeding up platforms that requires a depth buffer. */
|
||||
/* NOTE: This removes the possibility of using gl_FragDepth. */
|
||||
.early_fragment_test(true)
|
||||
.vertex_out(eevee_surf_shadow_atomic_iface)
|
||||
.storage_buf(SHADOW_RENDER_MAP_BUF_SLOT,
|
||||
Qualifier::READ,
|
||||
|
@ -268,6 +265,9 @@ GPU_SHADER_CREATE_INFO(eevee_surf_shadow_tbdr)
|
|||
.additional_info("eevee_surf_shadow")
|
||||
.define("SHADOW_UPDATE_TBDR")
|
||||
.builtins(BuiltinBits::LAYER)
|
||||
/* Use greater depth write to avoid loosing the early Z depth test but ensure correct fragment
|
||||
ordering after slope bias. */
|
||||
.depth_write(DepthWrite::GREATER)
|
||||
/* F32 color attachment for on-tile depth accumulation without atomics. */
|
||||
.fragment_out(0, Type::FLOAT, "out_depth", DualBlend::NONE, SHADOW_ROG_ID);
|
||||
|
||||
|
|
|
@ -525,8 +525,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd,
|
|||
const GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
|
||||
|
||||
const bool is_in_front = (ob->dtx & OB_DRAW_IN_FRONT);
|
||||
/* Grease Pencil 3 doesn't have this. */
|
||||
const bool is_screenspace = false;
|
||||
|
||||
const bool override_vertcol = (pd->v3d_color_type != -1);
|
||||
const bool is_vert_col_mode = (pd->v3d_color_type == V3D_SHADING_VERTEX_COLOR) ||
|
||||
(ob->mode == OB_MODE_VERTEX_PAINT) || pd->is_render;
|
||||
|
@ -541,9 +540,9 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd,
|
|||
const float vert_col_opacity = (override_vertcol) ?
|
||||
(is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) :
|
||||
(pd->is_render ? 1.0f : pd->vertex_paint_opacity);
|
||||
/* Negate thickness sign to tag that strokes are in screen space.
|
||||
* Convert to world units (by default, 1 meter = 1000 pixels). */
|
||||
const float thickness_scale = (is_screenspace) ? -1.0f : 1.0f / 1000.0f;
|
||||
/* Negate thickness sign to tag that strokes are in screen space (this is no longer used in
|
||||
* GPv3). Convert to world units (by default, 1 meter = 1000 pixels). */
|
||||
const float thickness_scale = blender::bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
/* If the layer is used as a mask (but is otherwise not visible in the render), render it with a
|
||||
* opacity of 0 so that it can still mask other layers. */
|
||||
const float layer_opacity = !is_used_as_mask ? grease_pencil_layer_final_opacity_get(
|
||||
|
|
|
@ -750,9 +750,9 @@ static void grease_pencil_geom_batch_ensure(Object &object,
|
|||
const float3 pos = math::transform_point(layer_space_to_object_space, positions[point_i]);
|
||||
copy_v3_v3(s_vert.pos, pos);
|
||||
s_vert.radius = radii[point_i] * ((end_cap == GP_STROKE_CAP_TYPE_ROUND) ? 1.0f : -1.0f);
|
||||
/* Convert to legacy "pixel" space. The shader expects the values to be in this space.
|
||||
* Otherwise the values will get clamped. */
|
||||
s_vert.radius *= 1000.0f;
|
||||
/* Convert to legacy "pixel" space. We divide here, because the shader expects the values to
|
||||
* be in the `px` space rather than world space. Otherwise the values will get clamped. */
|
||||
s_vert.radius /= bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR;
|
||||
s_vert.opacity = opacities[point_i] *
|
||||
((start_cap == GP_STROKE_CAP_TYPE_ROUND) ? 1.0f : -1.0f);
|
||||
s_vert.point_id = verts_range[idx];
|
||||
|
|
|
@ -383,7 +383,7 @@ PassType *drw_volume_object_mesh_init(PassType &ps,
|
|||
volume_infos.grids_xform[grid_id++] = float4x4::identity();
|
||||
}
|
||||
}
|
||||
else if (!fds->fluid) {
|
||||
else if (fds->fluid) {
|
||||
/* Smoke Simulation. */
|
||||
DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE);
|
||||
|
||||
|
|
|
@ -5142,7 +5142,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
|
|||
cfra = BKE_nla_tweakedit_remap(adt, float(scene->r.cfra), NLATIME_CONVERT_UNMAP);
|
||||
|
||||
/* Get flags for keyframing. */
|
||||
flag = ANIM_get_keyframing_flags(scene);
|
||||
flag = blender::animrig::get_keyframing_flags(scene);
|
||||
|
||||
/* try to resolve the path stored in the F-Curve */
|
||||
if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
|
||||
|
@ -5205,7 +5205,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
|
|||
key->adt, anim_eval_context.eval_time, NLATIME_CONVERT_UNMAP);
|
||||
|
||||
/* get flags for keyframing */
|
||||
flag = ANIM_get_keyframing_flags(scene);
|
||||
flag = blender::animrig::get_keyframing_flags(scene);
|
||||
|
||||
/* try to resolve the path stored in the F-Curve */
|
||||
if (RNA_path_resolve_property(&id_ptr, rna_path ? rna_path->c_str() : nullptr, &ptr, &prop)) {
|
||||
|
@ -5261,7 +5261,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void * /*id_poin*/
|
|||
cfra = float(scene->r.cfra);
|
||||
|
||||
/* get flags for keyframing */
|
||||
flag = ANIM_get_keyframing_flags(scene);
|
||||
flag = blender::animrig::get_keyframing_flags(scene);
|
||||
|
||||
/* Get pointer and property from the slider -
|
||||
* this should all match up with the NlaStrip required. */
|
||||
|
|
|
@ -70,31 +70,6 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op,
|
|||
|
||||
static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *ks);
|
||||
|
||||
/* ************************************************** */
|
||||
/* Keyframing Setting Wrangling */
|
||||
|
||||
eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene)
|
||||
{
|
||||
using namespace blender::animrig;
|
||||
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
|
||||
|
||||
/* Visual keying. */
|
||||
if (is_keying_flag(scene, KEYING_FLAG_VISUALKEY)) {
|
||||
flag |= INSERTKEY_MATRIX;
|
||||
}
|
||||
|
||||
/* Cycle-aware keyframe insertion - preserve cycle period and flow. */
|
||||
if (is_keying_flag(scene, KEYING_FLAG_CYCLEAWARE)) {
|
||||
flag |= INSERTKEY_CYCLE_AWARE;
|
||||
}
|
||||
|
||||
if (is_keying_flag(scene, MANUALKEY_FLAG_INSERTNEEDED)) {
|
||||
flag |= INSERTKEY_NEEDED;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/* ******************************************* */
|
||||
/* Animation Data Validation */
|
||||
|
||||
|
@ -389,7 +364,7 @@ static int insert_key(bContext *C, wmOperator *op)
|
|||
Scene *scene = CTX_data_scene(C);
|
||||
const float scene_frame = BKE_scene_frame_get(scene);
|
||||
|
||||
const eInsertKeyFlags insert_key_flags = ANIM_get_keyframing_flags(scene);
|
||||
const eInsertKeyFlags insert_key_flags = animrig::get_keyframing_flags(scene);
|
||||
const eBezTriple_KeyframeType key_type = eBezTriple_KeyframeType(
|
||||
scene->toolsettings->keyframe_type);
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
|
@ -976,7 +951,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
|
|||
const bool all = RNA_boolean_get(op->ptr, "all");
|
||||
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
|
||||
|
||||
flag = ANIM_get_keyframing_flags(scene);
|
||||
flag = get_keyframing_flags(scene);
|
||||
|
||||
if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) {
|
||||
/* pass event on if no active button found */
|
||||
|
|
|
@ -101,7 +101,7 @@ static int add_default_keyingset_exec(bContext *C, wmOperator * /*op*/)
|
|||
*/
|
||||
const eKS_Settings flag = KEYINGSET_ABSOLUTE;
|
||||
|
||||
const eInsertKeyFlags keyingflag = ANIM_get_keyframing_flags(scene);
|
||||
const eInsertKeyFlags keyingflag = blender::animrig::get_keyframing_flags(scene);
|
||||
|
||||
/* Call the API func, and set the active keyingset index. */
|
||||
BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, flag, keyingflag);
|
||||
|
@ -285,7 +285,7 @@ static int add_keyingset_button_exec(bContext *C, wmOperator *op)
|
|||
*/
|
||||
const eKS_Settings flag = KEYINGSET_ABSOLUTE;
|
||||
|
||||
const eInsertKeyFlags keyingflag = ANIM_get_keyframing_flags(scene);
|
||||
const eInsertKeyFlags keyingflag = blender::animrig::get_keyframing_flags(scene);
|
||||
|
||||
/* Call the API func, and set the active keyingset index. */
|
||||
keyingset = BKE_keyingset_add(
|
||||
|
@ -1136,7 +1136,7 @@ int ANIM_apply_keyingset(bContext *C,
|
|||
}
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const eInsertKeyFlags base_kflags = ANIM_get_keyframing_flags(scene);
|
||||
const eInsertKeyFlags base_kflags = blender::animrig::get_keyframing_flags(scene);
|
||||
eInsertKeyFlags kflag = INSERTKEY_NOFLAGS;
|
||||
if (mode == MODIFYKEY_MODE_INSERT) {
|
||||
/* use context settings as base */
|
||||
|
|
|
@ -834,6 +834,52 @@ static void updateDuplicateTransformConstraintSettings(Object *ob,
|
|||
mul_m4_v3(imat, trans->to_max_scale);
|
||||
}
|
||||
|
||||
static void track_axis_x_swap(int &value)
|
||||
{
|
||||
/* Swap track axis X <> -X. */
|
||||
if (value == TRACK_X) {
|
||||
value = TRACK_nX;
|
||||
}
|
||||
else if (value == TRACK_nX) {
|
||||
value = TRACK_X;
|
||||
}
|
||||
}
|
||||
|
||||
static void track_axis_x_swap(char &value)
|
||||
{
|
||||
/* Swap track axis X <> -X. */
|
||||
if (value == TRACK_X) {
|
||||
value = TRACK_nX;
|
||||
}
|
||||
else if (value == TRACK_nX) {
|
||||
value = TRACK_X;
|
||||
}
|
||||
}
|
||||
|
||||
static void updateDuplicateConstraintTrackToSettings(bConstraint *curcon)
|
||||
{
|
||||
bTrackToConstraint *data = static_cast<bTrackToConstraint *>(curcon->data);
|
||||
track_axis_x_swap(data->reserved1);
|
||||
}
|
||||
|
||||
static void updateDuplicateConstraintLockTrackSettings(bConstraint *curcon)
|
||||
{
|
||||
bLockTrackConstraint *data = static_cast<bLockTrackConstraint *>(curcon->data);
|
||||
track_axis_x_swap(data->trackflag);
|
||||
}
|
||||
|
||||
static void updateDuplicateConstraintDampTrackSettings(bConstraint *curcon)
|
||||
{
|
||||
bDampTrackConstraint *data = static_cast<bDampTrackConstraint *>(curcon->data);
|
||||
track_axis_x_swap(data->trackflag);
|
||||
}
|
||||
|
||||
static void updateDuplicateConstraintShrinkwrapSettings(bConstraint *curcon)
|
||||
{
|
||||
bShrinkwrapConstraint *data = static_cast<bShrinkwrapConstraint *>(curcon->data);
|
||||
track_axis_x_swap(data->trackAxis);
|
||||
}
|
||||
|
||||
static void updateDuplicateConstraintSettings(EditBone *dup_bone, EditBone *orig_bone, Object *ob)
|
||||
{
|
||||
/* If an edit bone has been duplicated, lets update its constraints if the
|
||||
|
@ -863,6 +909,18 @@ static void updateDuplicateConstraintSettings(EditBone *dup_bone, EditBone *orig
|
|||
case CONSTRAINT_TYPE_TRANSFORM:
|
||||
updateDuplicateTransformConstraintSettings(ob, pchan, curcon);
|
||||
break;
|
||||
case CONSTRAINT_TYPE_TRACKTO:
|
||||
updateDuplicateConstraintTrackToSettings(curcon);
|
||||
break;
|
||||
case CONSTRAINT_TYPE_LOCKTRACK:
|
||||
updateDuplicateConstraintLockTrackSettings(curcon);
|
||||
break;
|
||||
case CONSTRAINT_TYPE_DAMPTRACK:
|
||||
updateDuplicateConstraintDampTrackSettings(curcon);
|
||||
break;
|
||||
case CONSTRAINT_TYPE_SHRINKWRAP:
|
||||
updateDuplicateConstraintShrinkwrapSettings(curcon);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ void send_redraw_notifier(const bContext &C)
|
|||
|
||||
static bool asset_shelf_type_poll(const bContext &C,
|
||||
const SpaceType &space_type,
|
||||
AssetShelfType *shelf_type)
|
||||
const AssetShelfType *shelf_type)
|
||||
{
|
||||
if (!shelf_type) {
|
||||
return false;
|
||||
|
@ -70,13 +70,13 @@ static bool asset_shelf_type_poll(const bContext &C,
|
|||
return !shelf_type->poll || shelf_type->poll(&C, shelf_type);
|
||||
}
|
||||
|
||||
static AssetShelfType *asset_shelf_type_ensure(SpaceType &space_type, AssetShelf &shelf)
|
||||
static AssetShelfType *asset_shelf_type_ensure(const SpaceType &space_type, AssetShelf &shelf)
|
||||
{
|
||||
if (shelf.type) {
|
||||
return shelf.type;
|
||||
}
|
||||
|
||||
for (std::unique_ptr<AssetShelfType> &shelf_type : space_type.asset_shelf_types) {
|
||||
for (const std::unique_ptr<AssetShelfType> &shelf_type : space_type.asset_shelf_types) {
|
||||
if (STREQ(shelf.idname, shelf_type->idname)) {
|
||||
shelf.type = shelf_type.get();
|
||||
return shelf_type.get();
|
||||
|
@ -137,7 +137,7 @@ static void activate_shelf(RegionAssetShelf &shelf_regiondata, AssetShelf &shelf
|
|||
* current context (all polls failed).
|
||||
*/
|
||||
static AssetShelf *update_active_shelf(const bContext &C,
|
||||
SpaceType &space_type,
|
||||
const SpaceType &space_type,
|
||||
RegionAssetShelf &shelf_regiondata)
|
||||
{
|
||||
/* Note: Don't access #AssetShelf.type directly, use #asset_shelf_type_ensure(). */
|
||||
|
@ -167,7 +167,7 @@ static AssetShelf *update_active_shelf(const bContext &C,
|
|||
}
|
||||
|
||||
/* Case 3: */
|
||||
for (std::unique_ptr<AssetShelfType> &shelf_type : space_type.asset_shelf_types) {
|
||||
for (const std::unique_ptr<AssetShelfType> &shelf_type : space_type.asset_shelf_types) {
|
||||
if (asset_shelf_type_poll(C, space_type, shelf_type.get())) {
|
||||
AssetShelf *new_shelf = create_shelf_from_type(*shelf_type);
|
||||
BLI_addhead(&shelf_regiondata.shelves, new_shelf);
|
||||
|
|
|
@ -31,7 +31,7 @@ void build_asset_view(uiLayout &layout,
|
|||
const AssetLibraryReference &library_ref,
|
||||
const AssetShelf &shelf,
|
||||
const bContext &C,
|
||||
ARegion ®ion);
|
||||
const ARegion ®ion);
|
||||
|
||||
void catalog_selector_panel_register(ARegionType *region_type);
|
||||
|
||||
|
|
|
@ -240,7 +240,7 @@ void build_asset_view(uiLayout &layout,
|
|||
const AssetLibraryReference &library_ref,
|
||||
const AssetShelf &shelf,
|
||||
const bContext &C,
|
||||
ARegion ®ion)
|
||||
const ARegion ®ion)
|
||||
{
|
||||
list::storage_fetch(&library_ref, &C);
|
||||
list::ensure_previews_job(&library_ref, &C);
|
||||
|
|
|
@ -394,6 +394,9 @@ static int run_node_group_exec(bContext *C, wmOperator *op)
|
|||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *active_object = CTX_data_active_object(C);
|
||||
/* Note: `region` and `rv3d` may be null when called from a script. */
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
const RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
if (!active_object) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
@ -470,6 +473,9 @@ static int run_node_group_exec(bContext *C, wmOperator *op)
|
|||
operator_eval_data.depsgraphs = &depsgraphs;
|
||||
operator_eval_data.self_object_orig = object;
|
||||
operator_eval_data.scene_orig = scene;
|
||||
RNA_int_get_array(op->ptr, "mouse_position", operator_eval_data.mouse_position);
|
||||
operator_eval_data.region_size = region ? int2(region->sizex, region->sizey) : int2(0);
|
||||
operator_eval_data.rv3d = rv3d;
|
||||
|
||||
nodes::GeoNodesCallData call_data{};
|
||||
call_data.operator_data = &operator_eval_data;
|
||||
|
@ -504,13 +510,15 @@ static int run_node_group_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int run_node_group_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
static int run_node_group_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
const bNodeTree *node_tree = get_node_group(*C, *op->ptr, op->reports);
|
||||
if (!node_tree) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
RNA_int_set_array(op->ptr, "mouse_position", event->mval);
|
||||
|
||||
nodes::update_input_properties_from_node_tree(*node_tree, op->properties, *op->properties);
|
||||
nodes::update_output_properties_from_node_tree(*node_tree, op->properties, *op->properties);
|
||||
|
||||
|
@ -695,8 +703,35 @@ static std::string run_node_group_get_name(wmOperatorType * /*ot*/, PointerRNA *
|
|||
return ref.drop_prefix(ref.find_last_of(SEP_STR) + 1);
|
||||
}
|
||||
|
||||
static bool run_node_group_depends_on_cursor(bContext &C, wmOperatorType & /*ot*/, PointerRNA *ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
return false;
|
||||
}
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
if (bNodeTree *group = reinterpret_cast<bNodeTree *>(
|
||||
WM_operator_properties_id_lookup_from_name_or_session_uid(&bmain, ptr, ID_NT)))
|
||||
{
|
||||
return group->geometry_node_asset_traits &&
|
||||
(group->geometry_node_asset_traits->flag & GEO_NODE_ASSET_WAIT_FOR_CURSOR) != 0;
|
||||
}
|
||||
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
asset::operator_asset_reference_props_get_asset_from_all_library(C, *ptr, nullptr);
|
||||
if (!asset) {
|
||||
return false;
|
||||
}
|
||||
const IDProperty *traits_flag = BKE_asset_metadata_idprop_find(
|
||||
&asset->get_metadata(), "geometry_node_asset_traits_flag");
|
||||
if (traits_flag == nullptr || !(IDP_Int(traits_flag) & GEO_NODE_ASSET_WAIT_FOR_CURSOR)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GEOMETRY_OT_execute_node_group(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
ot->name = "Run Node Group";
|
||||
ot->idname = __func__;
|
||||
ot->description = "Execute a node group on geometry";
|
||||
|
@ -708,11 +743,27 @@ void GEOMETRY_OT_execute_node_group(wmOperatorType *ot)
|
|||
ot->ui = run_node_group_ui;
|
||||
ot->ui_poll = run_node_ui_poll;
|
||||
ot->get_name = run_node_group_get_name;
|
||||
ot->depends_on_cursor = run_node_group_depends_on_cursor;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
asset::operator_asset_reference_props_register(*ot->srna);
|
||||
WM_operator_properties_id_lookup(ot, true);
|
||||
|
||||
/* Store the mouse position in an RNA property rather than allocated operator custom data in
|
||||
* order to support redoing the operator. Because redo uses `exec`, the mouse position will be in
|
||||
* the same position in screen space. */
|
||||
prop = RNA_def_int_array(ot->srna,
|
||||
"mouse_position",
|
||||
2,
|
||||
nullptr,
|
||||
INT_MIN,
|
||||
INT_MAX,
|
||||
"Mouse Position",
|
||||
"Mouse coordinates in region space",
|
||||
INT_MIN,
|
||||
INT_MAX);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -261,16 +261,12 @@ static int grease_pencil_stroke_simplify_exec(bContext *C, wmOperator *op)
|
|||
[positions, radii](int64_t first_index, int64_t last_index, int64_t index) {
|
||||
const float dist_position = dist_to_line_v3(
|
||||
positions[index], positions[first_index], positions[last_index]);
|
||||
/* We divide the distance by 2000.0f to convert from "pixels" to an actual
|
||||
* distance. For some reason, grease pencil strokes the thickness of strokes in
|
||||
* pixels rather than object space distance. */
|
||||
const float dist_radii = dist_to_interpolated(positions[index],
|
||||
positions[first_index],
|
||||
positions[last_index],
|
||||
radii[index],
|
||||
radii[first_index],
|
||||
radii[last_index]) /
|
||||
2000.0f;
|
||||
radii[last_index]);
|
||||
return math::max(dist_position, dist_radii);
|
||||
};
|
||||
|
||||
|
@ -2193,18 +2189,20 @@ static void GREASE_PENCIL_OT_separate(wmOperatorType *ot)
|
|||
* \{ */
|
||||
|
||||
/* Global clipboard for Grease Pencil curves. */
|
||||
struct Clipboard {
|
||||
static struct Clipboard {
|
||||
bke::CurvesGeometry curves;
|
||||
/* We store the material uid's of the copied curves, so we can match those when pasting the
|
||||
* clipboard into another object. */
|
||||
Vector<std::pair<uint, int>> materials;
|
||||
int materials_in_source_num;
|
||||
};
|
||||
} *grease_pencil_clipboard = nullptr;
|
||||
|
||||
static Clipboard &get_grease_pencil_clipboard()
|
||||
static Clipboard &ensure_grease_pencil_clipboard()
|
||||
{
|
||||
static Clipboard clipboard;
|
||||
return clipboard;
|
||||
if (grease_pencil_clipboard == nullptr) {
|
||||
grease_pencil_clipboard = MEM_new<Clipboard>(__func__);
|
||||
}
|
||||
return *grease_pencil_clipboard;
|
||||
}
|
||||
|
||||
static int grease_pencil_paste_strokes_exec(bContext *C, wmOperator *op)
|
||||
|
@ -2217,8 +2215,6 @@ static int grease_pencil_paste_strokes_exec(bContext *C, wmOperator *op)
|
|||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
const bool paste_on_back = RNA_boolean_get(op->ptr, "paste_back");
|
||||
|
||||
Clipboard &clipboard = get_grease_pencil_clipboard();
|
||||
|
||||
/* Get active layer in the target object. */
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No active Grease Pencil layer");
|
||||
|
@ -2231,7 +2227,8 @@ static int grease_pencil_paste_strokes_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
/* Ensure active keyframe. */
|
||||
if (!ensure_active_keyframe(scene, grease_pencil)) {
|
||||
bool inserted_keyframe = false;
|
||||
if (!ensure_active_keyframe(scene, grease_pencil, inserted_keyframe)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
@ -2251,63 +2248,15 @@ static int grease_pencil_paste_strokes_exec(bContext *C, wmOperator *op)
|
|||
selection_in_target.finish();
|
||||
});
|
||||
|
||||
/* Get a list of all materials in the scene. */
|
||||
Map<uint, Material *> scene_materials;
|
||||
LISTBASE_FOREACH (Material *, material, &bmain->materials) {
|
||||
scene_materials.add(material->id.session_uid, material);
|
||||
}
|
||||
clipboard_paste_strokes(*bmain, *object, *target_drawing, paste_on_back);
|
||||
|
||||
/* Map the materials used in the clipboard curves to the materials in the target object. */
|
||||
Array<int> clipboard_material_remap(clipboard.materials_in_source_num, 0);
|
||||
for (const int i : clipboard.materials.index_range()) {
|
||||
/* Check if the material name exists in the scene. */
|
||||
int target_index;
|
||||
uint material_id = clipboard.materials[i].first;
|
||||
Material *material = scene_materials.lookup_default(material_id, nullptr);
|
||||
if (!material) {
|
||||
/* Material is removed, so create a new material. */
|
||||
BKE_grease_pencil_object_material_new(bmain, object, nullptr, &target_index);
|
||||
clipboard_material_remap[clipboard.materials[i].second] = target_index;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find or add the material to the target object. */
|
||||
target_index = BKE_object_material_ensure(bmain, object, material);
|
||||
clipboard_material_remap[clipboard.materials[i].second] = target_index;
|
||||
}
|
||||
|
||||
/* Get the index range of the pasted curves in the target layer. */
|
||||
IndexRange pasted_curves_range = paste_on_back ?
|
||||
IndexRange(0, clipboard.curves.curves_num()) :
|
||||
IndexRange(target_drawing->strokes().curves_num(),
|
||||
clipboard.curves.curves_num());
|
||||
|
||||
/* Append the geometry from the clipboard to the target layer. */
|
||||
Curves *clipboard_curves = curves_new_nomain(clipboard.curves);
|
||||
Curves *target_curves = curves_new_nomain(std::move(target_drawing->strokes_for_write()));
|
||||
Array<bke::GeometrySet> geometry_sets = {
|
||||
bke::GeometrySet::from_curves(paste_on_back ? clipboard_curves : target_curves),
|
||||
bke::GeometrySet::from_curves(paste_on_back ? target_curves : clipboard_curves)};
|
||||
bke::GeometrySet joined_curves = geometry::join_geometries(geometry_sets, {});
|
||||
target_drawing->strokes_for_write() = std::move(
|
||||
joined_curves.get_curves_for_write()->geometry.wrap());
|
||||
|
||||
/* Remap the material indices of the pasted curves to the target object material indices. */
|
||||
bke::MutableAttributeAccessor attributes =
|
||||
target_drawing->strokes_for_write().attributes_for_write();
|
||||
bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
|
||||
"material_index", bke::AttrDomain::Curve);
|
||||
if (material_indices) {
|
||||
for (const int i : pasted_curves_range) {
|
||||
material_indices.span[i] = clipboard_material_remap[material_indices.span[i]];
|
||||
}
|
||||
material_indices.finish();
|
||||
}
|
||||
|
||||
target_drawing->tag_topology_changed();
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
|
||||
if (inserted_keyframe) {
|
||||
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -2319,7 +2268,7 @@ static int grease_pencil_copy_strokes_exec(bContext *C, wmOperator *op)
|
|||
const bke::AttrDomain selection_domain = ED_grease_pencil_selection_domain_get(
|
||||
scene->toolsettings);
|
||||
|
||||
Clipboard &clipboard = get_grease_pencil_clipboard();
|
||||
Clipboard &clipboard = ensure_grease_pencil_clipboard();
|
||||
|
||||
bool anything_copied = false;
|
||||
int num_copied = 0;
|
||||
|
@ -2400,8 +2349,7 @@ static bool grease_pencil_paste_strokes_poll(bContext *C)
|
|||
}
|
||||
|
||||
/* Check for curves in the Grease Pencil clipboard. */
|
||||
Clipboard &clipboard = get_grease_pencil_clipboard();
|
||||
return (clipboard.curves.curves_num() > 0);
|
||||
return (grease_pencil_clipboard && grease_pencil_clipboard->curves.curves_num() > 0);
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_paste(wmOperatorType *ot)
|
||||
|
@ -2439,6 +2387,94 @@ static void GREASE_PENCIL_OT_copy(wmOperatorType *ot)
|
|||
|
||||
/** \} */
|
||||
|
||||
void clipboard_free()
|
||||
{
|
||||
if (grease_pencil_clipboard) {
|
||||
MEM_delete(grease_pencil_clipboard);
|
||||
grease_pencil_clipboard = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const bke::CurvesGeometry &clipboard_curves()
|
||||
{
|
||||
using namespace blender::ed::greasepencil;
|
||||
return ensure_grease_pencil_clipboard().curves;
|
||||
}
|
||||
|
||||
static Array<int> clipboard_materials_remap(Main &bmain, Object &object)
|
||||
{
|
||||
using namespace blender::ed::greasepencil;
|
||||
|
||||
/* Get a list of all materials in the scene. */
|
||||
Map<uint, Material *> scene_materials;
|
||||
LISTBASE_FOREACH (Material *, material, &bmain.materials) {
|
||||
scene_materials.add(material->id.session_uid, material);
|
||||
}
|
||||
|
||||
Clipboard &clipboard = ensure_grease_pencil_clipboard();
|
||||
Array<int> clipboard_material_remap(clipboard.materials_in_source_num, 0);
|
||||
for (const int i : clipboard.materials.index_range()) {
|
||||
/* Check if the material name exists in the scene. */
|
||||
int target_index;
|
||||
uint material_id = clipboard.materials[i].first;
|
||||
Material *material = scene_materials.lookup_default(material_id, nullptr);
|
||||
if (!material) {
|
||||
/* Material is removed, so create a new material. */
|
||||
BKE_grease_pencil_object_material_new(&bmain, &object, nullptr, &target_index);
|
||||
clipboard_material_remap[clipboard.materials[i].second] = target_index;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find or add the material to the target object. */
|
||||
target_index = BKE_object_material_ensure(&bmain, &object, material);
|
||||
clipboard_material_remap[clipboard.materials[i].second] = target_index;
|
||||
}
|
||||
|
||||
return clipboard_material_remap;
|
||||
}
|
||||
|
||||
IndexRange clipboard_paste_strokes(Main &bmain,
|
||||
Object &object,
|
||||
bke::greasepencil::Drawing &drawing,
|
||||
const bool paste_back)
|
||||
{
|
||||
const bke::CurvesGeometry &clipboard_curves = ed::greasepencil::clipboard_curves();
|
||||
|
||||
/* Get a list of all materials in the scene. */
|
||||
const Array<int> clipboard_material_remap = ed::greasepencil::clipboard_materials_remap(bmain,
|
||||
object);
|
||||
|
||||
/* Get the index range of the pasted curves in the target layer. */
|
||||
const IndexRange pasted_curves_range = paste_back ?
|
||||
IndexRange(0, clipboard_curves.curves_num()) :
|
||||
IndexRange(drawing.strokes().curves_num(),
|
||||
clipboard_curves.curves_num());
|
||||
|
||||
/* Append the geometry from the clipboard to the target layer. */
|
||||
Curves *clipboard_id = bke::curves_new_nomain(clipboard_curves);
|
||||
Curves *target_id = curves_new_nomain(std::move(drawing.strokes_for_write()));
|
||||
const Array<bke::GeometrySet> geometry_sets = {
|
||||
bke::GeometrySet::from_curves(paste_back ? clipboard_id : target_id),
|
||||
bke::GeometrySet::from_curves(paste_back ? target_id : clipboard_id)};
|
||||
bke::GeometrySet joined_curves = geometry::join_geometries(geometry_sets, {});
|
||||
drawing.strokes_for_write() = std::move(joined_curves.get_curves_for_write()->geometry.wrap());
|
||||
|
||||
/* Remap the material indices of the pasted curves to the target object material indices. */
|
||||
bke::MutableAttributeAccessor attributes = drawing.strokes_for_write().attributes_for_write();
|
||||
bke::SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
|
||||
"material_index", bke::AttrDomain::Curve);
|
||||
if (material_indices) {
|
||||
for (const int i : pasted_curves_range) {
|
||||
material_indices.span[i] = clipboard_material_remap[material_indices.span[i]];
|
||||
}
|
||||
material_indices.finish();
|
||||
}
|
||||
|
||||
drawing.tag_topology_changed();
|
||||
|
||||
return pasted_curves_range;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::greasepencil
|
||||
|
||||
void ED_operatortypes_grease_pencil_edit()
|
||||
|
|
|
@ -335,7 +335,9 @@ void create_keyframe_edit_data_selected_frames_list(KeyframeEditData *ked,
|
|||
}
|
||||
}
|
||||
|
||||
bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil)
|
||||
bool ensure_active_keyframe(const Scene &scene,
|
||||
GreasePencil &grease_pencil,
|
||||
bool &r_inserted_keyframe)
|
||||
{
|
||||
const int current_frame = scene.r.cfra;
|
||||
bke::greasepencil::Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
|
@ -366,6 +368,7 @@ bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil)
|
|||
/* Otherwise we just insert a blank keyframe at the current frame. */
|
||||
grease_pencil.insert_blank_frame(active_layer, current_frame, 0, BEZT_KEYTYPE_KEYFRAME);
|
||||
}
|
||||
r_inserted_keyframe = true;
|
||||
}
|
||||
/* There should now always be a drawing at the current frame. */
|
||||
BLI_assert(active_layer.has_drawing_at(current_frame));
|
||||
|
|
|
@ -563,6 +563,47 @@ Vector<MutableDrawingInfo> retrieve_editable_drawings_from_layer(
|
|||
return editable_drawings;
|
||||
}
|
||||
|
||||
Vector<MutableDrawingInfo> retrieve_editable_drawings_from_layer_with_falloff(
|
||||
const Scene &scene,
|
||||
GreasePencil &grease_pencil,
|
||||
const blender::bke::greasepencil::Layer &layer)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
const int current_frame = scene.r.cfra;
|
||||
const ToolSettings *toolsettings = scene.toolsettings;
|
||||
const bool use_multi_frame_editing = (toolsettings->gpencil_flags &
|
||||
GP_USE_MULTI_FRAME_EDITING) != 0;
|
||||
const bool use_multi_frame_falloff = use_multi_frame_editing &&
|
||||
(toolsettings->gp_sculpt.flag &
|
||||
GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
|
||||
const int layer_index = *grease_pencil.get_layer_index(layer);
|
||||
int center_frame;
|
||||
std::pair<int, int> minmax_frame;
|
||||
if (use_multi_frame_falloff) {
|
||||
BKE_curvemapping_init(toolsettings->gp_sculpt.cur_falloff);
|
||||
minmax_frame = get_minmax_selected_frame_numbers(grease_pencil, current_frame);
|
||||
center_frame = math::clamp(current_frame, minmax_frame.first, minmax_frame.second);
|
||||
}
|
||||
|
||||
Vector<MutableDrawingInfo> editable_drawings;
|
||||
const Array<int> frame_numbers = get_editable_frames_for_layer(
|
||||
layer, current_frame, use_multi_frame_editing);
|
||||
for (const int frame_number : frame_numbers) {
|
||||
if (Drawing *drawing = grease_pencil.get_editable_drawing_at(layer, frame_number)) {
|
||||
const float falloff = use_multi_frame_falloff ?
|
||||
get_multi_frame_falloff(frame_number,
|
||||
center_frame,
|
||||
minmax_frame.first,
|
||||
minmax_frame.second,
|
||||
toolsettings->gp_sculpt.cur_falloff) :
|
||||
1.0f;
|
||||
editable_drawings.append({*drawing, layer_index, frame_number, falloff});
|
||||
}
|
||||
}
|
||||
|
||||
return editable_drawings;
|
||||
}
|
||||
|
||||
Vector<DrawingInfo> retrieve_visible_drawings(const Scene &scene,
|
||||
const GreasePencil &grease_pencil,
|
||||
const bool do_onion_skinning)
|
||||
|
@ -1131,11 +1172,14 @@ int grease_pencil_draw_operator_invoke(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
/* Ensure a drawing at the current keyframe. */
|
||||
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil)) {
|
||||
bool inserted_keyframe = false;
|
||||
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil, inserted_keyframe)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (inserted_keyframe) {
|
||||
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
|
||||
}
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ struct ViewContext;
|
|||
namespace blender {
|
||||
namespace bke {
|
||||
enum class AttrDomain : int8_t;
|
||||
}
|
||||
class CurvesGeometry;
|
||||
} // namespace bke
|
||||
} // namespace blender
|
||||
|
||||
enum {
|
||||
|
@ -62,6 +63,7 @@ void ED_primitivetool_modal_keymap(wmKeyConfig *keyconf);
|
|||
void GREASE_PENCIL_OT_stroke_cutter(wmOperatorType *ot);
|
||||
|
||||
void ED_undosys_type_grease_pencil(UndoType *undo_type);
|
||||
|
||||
/**
|
||||
* Get the selection mode for Grease Pencil selection operators: point, stroke, segment.
|
||||
*/
|
||||
|
@ -207,7 +209,9 @@ bool has_any_frame_selected(const bke::greasepencil::Layer &layer);
|
|||
* create one when auto-key is on (taking additive drawing setting into account).
|
||||
* \return false when no keyframe could be found or created.
|
||||
*/
|
||||
bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil);
|
||||
bool ensure_active_keyframe(const Scene &scene,
|
||||
GreasePencil &grease_pencil,
|
||||
bool &r_inserted_keyframe);
|
||||
|
||||
void create_keyframe_edit_data_selected_frames_list(KeyframeEditData *ked,
|
||||
const bke::greasepencil::Layer &layer);
|
||||
|
@ -256,6 +260,8 @@ Array<Vector<MutableDrawingInfo>> retrieve_editable_drawings_grouped_per_frame(
|
|||
const Scene &scene, GreasePencil &grease_pencil);
|
||||
Vector<MutableDrawingInfo> retrieve_editable_drawings_from_layer(
|
||||
const Scene &scene, GreasePencil &grease_pencil, const bke::greasepencil::Layer &layer);
|
||||
Vector<MutableDrawingInfo> retrieve_editable_drawings_from_layer_with_falloff(
|
||||
const Scene &scene, GreasePencil &grease_pencil, const bke::greasepencil::Layer &layer);
|
||||
Vector<DrawingInfo> retrieve_visible_drawings(const Scene &scene,
|
||||
const GreasePencil &grease_pencil,
|
||||
bool do_onion_skinning);
|
||||
|
@ -381,4 +387,16 @@ void normalize_vertex_weights(MDeformVert &dvert,
|
|||
Span<bool> vertex_group_is_locked,
|
||||
Span<bool> vertex_group_is_bone_deformed);
|
||||
|
||||
void clipboard_free();
|
||||
const bke::CurvesGeometry &clipboard_curves();
|
||||
/**
|
||||
* Paste curves from the clipboard into the drawing.
|
||||
* \param paste_back Render behind existing curves by inserting curves at the front.
|
||||
* \return Index range of the new curves in the drawing after pasting.
|
||||
*/
|
||||
IndexRange clipboard_paste_strokes(Main &bmain,
|
||||
Object &object,
|
||||
bke::greasepencil::Drawing &drawing,
|
||||
bool paste_back);
|
||||
|
||||
} // namespace blender::ed::greasepencil
|
||||
|
|
|
@ -39,15 +39,6 @@ struct NlaKeyframingContext;
|
|||
/** \name Key-Framing Management
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Get the active settings for key-framing settings from context (specifically the given scene)
|
||||
* \param use_autokey_mode: include settings from key-framing mode in the result
|
||||
* (i.e. replace only).
|
||||
*/
|
||||
eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene);
|
||||
|
||||
/* -------- */
|
||||
|
||||
/**
|
||||
* \brief Lesser Key-framing API call.
|
||||
*
|
||||
|
|
|
@ -68,7 +68,9 @@ bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool
|
|||
if (but->type == UI_BTYPE_LABEL) {
|
||||
if (for_tooltip) {
|
||||
/* It's important labels are considered interactive for the purpose of showing tooltip. */
|
||||
if (!ui_but_drag_is_draggable(but) && but->tip_func == nullptr) {
|
||||
if (!ui_but_drag_is_draggable(but) && but->tip_func == nullptr &&
|
||||
(but->tip == nullptr || but->tip[0] == '\0'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -577,8 +577,7 @@ static int collection_exporter_export(bContext *C,
|
|||
filepath, sizeof(filepath), "//", fh->get_default_filename(collection_name).c_str());
|
||||
}
|
||||
else {
|
||||
char filename[FILENAME_MAX];
|
||||
BLI_path_split_file_part(filepath, filename, sizeof(filename));
|
||||
const char *filename = BLI_path_basename(filepath);
|
||||
if (!filename[0] || !BLI_path_extension(filename)) {
|
||||
BKE_reportf(op->reports, RPT_ERROR, "File path '%s' is not a valid file", filepath);
|
||||
|
||||
|
|
|
@ -43,6 +43,16 @@ set(SRC
|
|||
grease_pencil_draw_ops.cc
|
||||
grease_pencil_erase.cc
|
||||
grease_pencil_paint.cc
|
||||
grease_pencil_sculpt_clone.cc
|
||||
grease_pencil_sculpt_common.cc
|
||||
grease_pencil_sculpt_grab.cc
|
||||
grease_pencil_sculpt_pinch.cc
|
||||
grease_pencil_sculpt_push.cc
|
||||
grease_pencil_sculpt_randomize.cc
|
||||
grease_pencil_sculpt_smooth.cc
|
||||
grease_pencil_sculpt_strength.cc
|
||||
grease_pencil_sculpt_thickness.cc
|
||||
grease_pencil_sculpt_twist.cc
|
||||
grease_pencil_tint.cc
|
||||
grease_pencil_weight_average.cc
|
||||
grease_pencil_weight_blur.cc
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "WM_message.hh"
|
||||
#include "WM_toolsystem.hh"
|
||||
|
||||
#include "curves_sculpt_intern.hh"
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
|
@ -208,30 +209,31 @@ static bool grease_pencil_sculpt_paint_poll(bContext *C)
|
|||
return true;
|
||||
}
|
||||
|
||||
static GreasePencilStrokeOperation *grease_pencil_sculpt_paint_operation(bContext &C)
|
||||
static GreasePencilStrokeOperation *grease_pencil_sculpt_paint_operation(
|
||||
bContext &C, const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
const GpSculptPaint &gp_sculptpaint = *scene.toolsettings->gp_sculptpaint;
|
||||
const Brush &brush = *BKE_paint_brush_for_read(&gp_sculptpaint.paint);
|
||||
switch (eBrushGPSculptTool(brush.gpencil_sculpt_tool)) {
|
||||
case GPSCULPT_TOOL_SMOOTH:
|
||||
return nullptr;
|
||||
return greasepencil::new_smooth_operation(stroke_mode).release();
|
||||
case GPSCULPT_TOOL_THICKNESS:
|
||||
return nullptr;
|
||||
return greasepencil::new_thickness_operation(stroke_mode).release();
|
||||
case GPSCULPT_TOOL_STRENGTH:
|
||||
return nullptr;
|
||||
return greasepencil::new_strength_operation(stroke_mode).release();
|
||||
case GPSCULPT_TOOL_GRAB:
|
||||
return nullptr;
|
||||
return greasepencil::new_grab_operation(stroke_mode).release();
|
||||
case GPSCULPT_TOOL_PUSH:
|
||||
return nullptr;
|
||||
return greasepencil::new_push_operation(stroke_mode).release();
|
||||
case GPSCULPT_TOOL_TWIST:
|
||||
return nullptr;
|
||||
return greasepencil::new_twist_operation(stroke_mode).release();
|
||||
case GPSCULPT_TOOL_PINCH:
|
||||
return nullptr;
|
||||
return greasepencil::new_pinch_operation(stroke_mode).release();
|
||||
case GPSCULPT_TOOL_RANDOMIZE:
|
||||
return nullptr;
|
||||
return greasepencil::new_randomize_operation(stroke_mode).release();
|
||||
case GPSCULPT_TOOL_CLONE:
|
||||
return nullptr;
|
||||
return greasepencil::new_clone_operation(stroke_mode).release();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -240,7 +242,8 @@ static bool grease_pencil_sculpt_paint_test_start(bContext *C,
|
|||
wmOperator *op,
|
||||
const float mouse[2])
|
||||
{
|
||||
GreasePencilStrokeOperation *operation = grease_pencil_sculpt_paint_operation(*C);
|
||||
const BrushStrokeMode stroke_mode = BrushStrokeMode(RNA_enum_get(op->ptr, "mode"));
|
||||
GreasePencilStrokeOperation *operation = grease_pencil_sculpt_paint_operation(*C, stroke_mode);
|
||||
if (operation) {
|
||||
stroke_start(*C, *op, float2(mouse), *operation);
|
||||
return true;
|
||||
|
@ -276,10 +279,14 @@ static int grease_pencil_sculpt_paint_invoke(bContext *C, wmOperator *op, const
|
|||
}
|
||||
|
||||
/* Ensure a drawing at the current keyframe. */
|
||||
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil)) {
|
||||
bool inserted_keyframe = false;
|
||||
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil, inserted_keyframe)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (inserted_keyframe) {
|
||||
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
|
||||
}
|
||||
|
||||
op->customdata = paint_stroke_new(C,
|
||||
op,
|
||||
|
|
|
@ -4,9 +4,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "ED_grease_pencil.hh"
|
||||
|
||||
#include "paint_intern.hh"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
namespace blender::bke::greasepencil {
|
||||
class Drawing;
|
||||
class Layer;
|
||||
} // namespace blender::bke::greasepencil
|
||||
namespace blender::bke::crazyspace {
|
||||
struct GeometryDeformation;
|
||||
}
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
|
@ -25,6 +34,94 @@ class GreasePencilStrokeOperation {
|
|||
|
||||
namespace greasepencil {
|
||||
|
||||
/* Get list of drawings the tool should be operating on. */
|
||||
Vector<ed::greasepencil::MutableDrawingInfo> get_drawings_for_sculpt(const bContext &C);
|
||||
|
||||
/* Make sure the brush has all necessary grease pencil settings. */
|
||||
void init_brush(Brush &brush);
|
||||
|
||||
/* Index mask of all points within the brush radius. */
|
||||
IndexMask brush_influence_mask(const Scene &scene,
|
||||
const Brush &brush,
|
||||
const float2 &mouse_position,
|
||||
float pressure,
|
||||
float multi_frame_falloff,
|
||||
const IndexMask &selection,
|
||||
Span<float2> view_positions,
|
||||
Vector<float> &influences,
|
||||
IndexMaskMemory &memory);
|
||||
|
||||
/* Influence value at point co for the brush. */
|
||||
float brush_influence(const Scene &scene,
|
||||
const Brush &brush,
|
||||
const float2 &co,
|
||||
const InputSample &sample,
|
||||
float multi_frame_falloff);
|
||||
|
||||
/* True if influence of the brush should be inverted. */
|
||||
bool is_brush_inverted(const Brush &brush, BrushStrokeMode stroke_mode);
|
||||
|
||||
/* Common parameters for stroke callbacks that can be passed to utility functions. */
|
||||
struct GreasePencilStrokeParams {
|
||||
const ToolSettings &toolsettings;
|
||||
const ARegion ®ion;
|
||||
Object &ob_orig;
|
||||
Object &ob_eval;
|
||||
const bke::greasepencil::Layer &layer;
|
||||
int layer_index;
|
||||
int frame_number;
|
||||
float multi_frame_falloff;
|
||||
ed::greasepencil::DrawingPlacement placement;
|
||||
bke::greasepencil::Drawing &drawing;
|
||||
|
||||
/* Note: accessing region in worker threads will return null,
|
||||
* this has to be done on the main thread and passed explicitly. */
|
||||
static GreasePencilStrokeParams from_context(const Scene &scene,
|
||||
const Depsgraph &depsgraph,
|
||||
const ARegion ®ion,
|
||||
const View3D &view3d,
|
||||
Object &object,
|
||||
int layer_index,
|
||||
int frame_number,
|
||||
float multi_frame_falloff,
|
||||
bke::greasepencil::Drawing &drawing);
|
||||
};
|
||||
|
||||
/* Point index mask for a drawing based on selection tool settings. */
|
||||
IndexMask point_selection_mask(const GreasePencilStrokeParams ¶ms, IndexMaskMemory &memory);
|
||||
|
||||
bke::crazyspace::GeometryDeformation get_drawing_deformation(
|
||||
const GreasePencilStrokeParams ¶ms);
|
||||
|
||||
/* Project points from layer space into 2D view space. */
|
||||
Array<float2> calculate_view_positions(const GreasePencilStrokeParams ¶ms,
|
||||
const IndexMask &selection);
|
||||
|
||||
/* Stroke operation base class that performs various common initializations. */
|
||||
class GreasePencilStrokeOperationCommon : public GreasePencilStrokeOperation {
|
||||
public:
|
||||
using MutableDrawingInfo = blender::ed::greasepencil::MutableDrawingInfo;
|
||||
using DrawingPlacement = ed::greasepencil::DrawingPlacement;
|
||||
|
||||
BrushStrokeMode stroke_mode;
|
||||
|
||||
/* Previous mouse position for computing the direction. */
|
||||
float2 prev_mouse_position;
|
||||
|
||||
GreasePencilStrokeOperationCommon(const BrushStrokeMode stroke_mode) : stroke_mode(stroke_mode)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_inverted(const Brush &brush) const;
|
||||
float2 mouse_delta(const InputSample &input_sample) const;
|
||||
|
||||
void init_stroke(const bContext &C, const InputSample &start_sample);
|
||||
void stroke_extended(const InputSample &extension_sample);
|
||||
|
||||
void foreach_editable_drawing(
|
||||
const bContext &C, FunctionRef<bool(const GreasePencilStrokeParams ¶ms)> fn) const;
|
||||
};
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_paint_operation();
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_erase_operation();
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_tint_operation();
|
||||
|
@ -33,6 +130,15 @@ std::unique_ptr<GreasePencilStrokeOperation> new_weight_paint_draw_operation(
|
|||
std::unique_ptr<GreasePencilStrokeOperation> new_weight_paint_blur_operation();
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_weight_paint_average_operation();
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_weight_paint_smear_operation();
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_smooth_operation(BrushStrokeMode stroke_mode);
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_thickness_operation(BrushStrokeMode stroke_mode);
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_strength_operation(BrushStrokeMode stroke_mode);
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_randomize_operation(BrushStrokeMode stroke_mode);
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_grab_operation(BrushStrokeMode stroke_mode);
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_push_operation(BrushStrokeMode stroke_mode);
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_pinch_operation(BrushStrokeMode stroke_mode);
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_twist_operation(BrushStrokeMode stroke_mode);
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_clone_operation(BrushStrokeMode stroke_mode);
|
||||
|
||||
} // namespace greasepencil
|
||||
|
||||
|
|
|
@ -331,13 +331,14 @@ struct PaintOperationExecutor {
|
|||
* stable) fit. */
|
||||
Array<float2> coords_pre_blur(smooth_window.size());
|
||||
const int pre_blur_iterations = 3;
|
||||
geometry::gaussian_blur_1D(coords_to_smooth,
|
||||
pre_blur_iterations,
|
||||
settings_->active_smooth,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
coords_pre_blur.as_mutable_span());
|
||||
geometry::gaussian_blur_1D(
|
||||
coords_to_smooth,
|
||||
pre_blur_iterations,
|
||||
VArray<float>::ForSingle(settings_->active_smooth, smooth_window.size()),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
coords_pre_blur.as_mutable_span());
|
||||
|
||||
/* Curve fitting. The output will be a set of handles (float2 triplets) in a flat array. */
|
||||
const float max_error_threshold_px = 5.0f;
|
||||
|
@ -708,7 +709,7 @@ void PaintOperation::on_stroke_done(const bContext &C)
|
|||
drawing.tag_topology_changed();
|
||||
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, &grease_pencil.id);
|
||||
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil.id);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_paint_operation()
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "ED_curves.hh"
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
class CloneOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
static float2 arithmetic_mean(Span<float2> values)
|
||||
{
|
||||
return std::accumulate(values.begin(), values.end(), float2(0)) / values.size();
|
||||
}
|
||||
|
||||
void CloneOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
Object &object = *CTX_data_active_object(&C);
|
||||
|
||||
this->init_stroke(C, start_sample);
|
||||
|
||||
/* Note: Only one copy is created at the beginning of each stroke.
|
||||
* GPv2 supposedly has 2 modes:
|
||||
* - Stamp: Clone on stroke start and then transform (the transform part doesn't work)
|
||||
* - Continuous: Create multiple copies during the stroke (disabled)
|
||||
*
|
||||
* Here we only have the GPv2 behavior that actually works for now. */
|
||||
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams ¶ms) {
|
||||
const IndexRange pasted_curves = ed::greasepencil::clipboard_paste_strokes(
|
||||
bmain, object, params.drawing, false);
|
||||
if (pasted_curves.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
|
||||
const OffsetIndices<int> pasted_points_by_curve = curves.points_by_curve().slice(
|
||||
pasted_curves);
|
||||
const IndexRange pasted_points = IndexRange::from_begin_size(
|
||||
pasted_points_by_curve[0].start(),
|
||||
pasted_points_by_curve.total_size() - pasted_points_by_curve[0].start());
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, pasted_points);
|
||||
const float2 center = arithmetic_mean(view_positions.as_mutable_span().slice(pasted_points));
|
||||
const float2 &mouse_delta = start_sample.mouse_position - center;
|
||||
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
threading::parallel_for(pasted_points, 4096, [&](const IndexRange range) {
|
||||
for (const int point_i : range) {
|
||||
positions[point_i] = params.placement.project(view_positions[point_i] + mouse_delta);
|
||||
}
|
||||
});
|
||||
params.drawing.tag_positions_changed();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void CloneOperation::on_stroke_extended(const bContext & /*C*/,
|
||||
const InputSample &extension_sample)
|
||||
{
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_clone_operation(const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<CloneOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,284 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_brush.hh"
|
||||
#include "BKE_colortools.hh"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_crazyspace.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
#include "BLI_index_mask.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_node_tree_interface_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
Vector<ed::greasepencil::MutableDrawingInfo> get_drawings_for_sculpt(const bContext &C)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Object &ob_orig = *CTX_data_active_object(&C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
const Brush &brush = *BKE_paint_brush(&paint);
|
||||
const bool active_layer_only = ((brush.gpencil_settings->flag & GP_BRUSH_ACTIVE_LAYER_ONLY) !=
|
||||
0);
|
||||
|
||||
if (active_layer_only) {
|
||||
/* Apply only to the drawing at the current frame of the active layer. */
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
return {};
|
||||
}
|
||||
const Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
return ed::greasepencil::retrieve_editable_drawings_from_layer_with_falloff(
|
||||
scene, grease_pencil, active_layer);
|
||||
}
|
||||
|
||||
/* Apply to all editable drawings. */
|
||||
return ed::greasepencil::retrieve_editable_drawings_with_falloff(scene, grease_pencil);
|
||||
}
|
||||
|
||||
void init_brush(Brush &brush)
|
||||
{
|
||||
if (brush.gpencil_settings == nullptr) {
|
||||
BKE_brush_init_gpencil_settings(&brush);
|
||||
}
|
||||
BLI_assert(brush.gpencil_settings != nullptr);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_strength);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_sensitivity);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_jitter);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_rand_pressure);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_rand_strength);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_rand_uv);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_rand_hue);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_rand_saturation);
|
||||
BKE_curvemapping_init(brush.gpencil_settings->curve_rand_value);
|
||||
}
|
||||
|
||||
static float brush_radius(const Scene &scene, const Brush &brush, const float pressure = 1.0f)
|
||||
{
|
||||
float radius = BKE_brush_size_get(&scene, &brush);
|
||||
if (BKE_brush_use_size_pressure(&brush)) {
|
||||
radius *= BKE_curvemapping_evaluateF(brush.gpencil_settings->curve_sensitivity, 0, pressure);
|
||||
}
|
||||
return radius;
|
||||
}
|
||||
|
||||
float brush_influence(const Scene &scene,
|
||||
const Brush &brush,
|
||||
const float2 &co,
|
||||
const InputSample &sample,
|
||||
const float multi_frame_falloff)
|
||||
{
|
||||
const float radius = brush_radius(scene, brush, sample.pressure);
|
||||
/* Basic strength factor from brush settings. */
|
||||
const float brush_pressure = BKE_brush_use_alpha_pressure(&brush) ? sample.pressure : 1.0f;
|
||||
const float influence_base = BKE_brush_alpha_get(&scene, &brush) * brush_pressure *
|
||||
multi_frame_falloff;
|
||||
|
||||
/* Distance falloff. */
|
||||
const int2 mval_i = int2(math::round(sample.mouse_position));
|
||||
const float distance = math::distance(mval_i, int2(co));
|
||||
/* Apply Brush curve. */
|
||||
const float brush_falloff = BKE_brush_curve_strength(&brush, distance, radius);
|
||||
|
||||
return influence_base * brush_falloff;
|
||||
}
|
||||
|
||||
IndexMask brush_influence_mask(const Scene &scene,
|
||||
const Brush &brush,
|
||||
const float2 &mouse_position,
|
||||
const float pressure,
|
||||
const float multi_frame_falloff,
|
||||
const IndexMask &selection,
|
||||
const Span<float2> view_positions,
|
||||
Vector<float> &influences,
|
||||
IndexMaskMemory &memory)
|
||||
{
|
||||
if (selection.is_empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const float radius = brush_radius(scene, brush, pressure);
|
||||
const float radius_squared = radius * radius;
|
||||
const float brush_pressure = BKE_brush_use_alpha_pressure(&brush) ? pressure : 1.0f;
|
||||
const float influence_base = BKE_brush_alpha_get(&scene, &brush) * brush_pressure *
|
||||
multi_frame_falloff;
|
||||
const int2 mval_i = int2(math::round(mouse_position));
|
||||
|
||||
Array<float> all_influences(selection.min_array_size());
|
||||
const IndexMask influence_mask = IndexMask::from_predicate(
|
||||
selection, GrainSize(4096), memory, [&](const int point) {
|
||||
/* Distance falloff. */
|
||||
const float distance_squared = math::distance_squared(int2(view_positions[point]), mval_i);
|
||||
if (distance_squared > radius_squared) {
|
||||
all_influences[point] = 0.0f;
|
||||
return false;
|
||||
}
|
||||
/* Apply Brush curve. */
|
||||
const float brush_falloff = BKE_brush_curve_strength(
|
||||
&brush, math::sqrt(distance_squared), radius);
|
||||
all_influences[point] = influence_base * brush_falloff;
|
||||
return all_influences[point] > 0.0f;
|
||||
});
|
||||
influences.reinitialize(influence_mask.size());
|
||||
array_utils::gather(all_influences.as_span(), influence_mask, influences.as_mutable_span());
|
||||
|
||||
return influence_mask;
|
||||
}
|
||||
|
||||
bool is_brush_inverted(const Brush &brush, const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
/* The basic setting is the brush's setting. During runtime, the user can hold down the Ctrl key
|
||||
* to invert the basic behavior. */
|
||||
return bool(brush.flag & BRUSH_DIR_IN) ^ (stroke_mode == BrushStrokeMode::BRUSH_STROKE_INVERT);
|
||||
}
|
||||
|
||||
GreasePencilStrokeParams GreasePencilStrokeParams::from_context(
|
||||
const Scene &scene,
|
||||
const Depsgraph &depsgraph,
|
||||
const ARegion ®ion,
|
||||
const View3D &view3d,
|
||||
Object &object,
|
||||
const int layer_index,
|
||||
const int frame_number,
|
||||
const float multi_frame_falloff,
|
||||
bke::greasepencil::Drawing &drawing)
|
||||
{
|
||||
Object &ob_eval = *DEG_get_evaluated_object(&depsgraph, &object);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
|
||||
|
||||
const bke::greasepencil::Layer &layer = *grease_pencil.layers()[layer_index];
|
||||
ed::greasepencil::DrawingPlacement placement(scene, region, view3d, ob_eval, layer);
|
||||
|
||||
return {*scene.toolsettings,
|
||||
region,
|
||||
object,
|
||||
ob_eval,
|
||||
layer,
|
||||
layer_index,
|
||||
frame_number,
|
||||
multi_frame_falloff,
|
||||
std::move(placement),
|
||||
drawing};
|
||||
}
|
||||
|
||||
IndexMask point_selection_mask(const GreasePencilStrokeParams ¶ms, IndexMaskMemory &memory)
|
||||
{
|
||||
const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
|
||||
eGP_Sculpt_SelectMaskFlag(params.toolsettings.gpencil_selectmode_sculpt));
|
||||
return (is_masking ? ed::greasepencil::retrieve_editable_and_selected_points(
|
||||
params.ob_eval, params.drawing, memory) :
|
||||
params.drawing.strokes().points_range());
|
||||
}
|
||||
|
||||
bke::crazyspace::GeometryDeformation get_drawing_deformation(
|
||||
const GreasePencilStrokeParams ¶ms)
|
||||
{
|
||||
return bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
¶ms.ob_eval, params.ob_orig, params.layer_index, params.frame_number);
|
||||
}
|
||||
|
||||
Array<float2> calculate_view_positions(const GreasePencilStrokeParams ¶ms,
|
||||
const IndexMask &selection)
|
||||
{
|
||||
bke::crazyspace::GeometryDeformation deformation = get_drawing_deformation(params);
|
||||
|
||||
Array<float2> view_positions(deformation.positions.size());
|
||||
|
||||
/* Compute screen space positions. */
|
||||
const float4x4 transform = params.layer.to_world_space(params.ob_eval);
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
eV3DProjStatus result = ED_view3d_project_float_global(
|
||||
¶ms.region,
|
||||
math::transform_point(transform, deformation.positions[point_i]),
|
||||
view_positions[point_i],
|
||||
V3D_PROJ_TEST_NOP);
|
||||
if (result != V3D_PROJ_RET_OK) {
|
||||
view_positions[point_i] = float2(0);
|
||||
}
|
||||
});
|
||||
|
||||
return view_positions;
|
||||
}
|
||||
|
||||
bool GreasePencilStrokeOperationCommon::is_inverted(const Brush &brush) const
|
||||
{
|
||||
return is_brush_inverted(brush, this->stroke_mode);
|
||||
}
|
||||
|
||||
float2 GreasePencilStrokeOperationCommon::mouse_delta(const InputSample &input_sample) const
|
||||
{
|
||||
return input_sample.mouse_position - this->prev_mouse_position;
|
||||
}
|
||||
|
||||
void GreasePencilStrokeOperationCommon::foreach_editable_drawing(
|
||||
const bContext &C, FunctionRef<bool(const GreasePencilStrokeParams ¶ms)> fn) const
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
|
||||
const View3D &view3d = *CTX_wm_view3d(&C);
|
||||
const ARegion ®ion = *CTX_wm_region(&C);
|
||||
Object &object = *CTX_data_active_object(&C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
|
||||
|
||||
std::atomic<bool> changed = false;
|
||||
const Vector<MutableDrawingInfo> drawings = get_drawings_for_sculpt(C);
|
||||
threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) {
|
||||
GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
|
||||
scene,
|
||||
depsgraph,
|
||||
region,
|
||||
view3d,
|
||||
object,
|
||||
info.layer_index,
|
||||
info.frame_number,
|
||||
info.multi_frame_falloff,
|
||||
info.drawing);
|
||||
if (fn(params)) {
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
}
|
||||
}
|
||||
|
||||
void GreasePencilStrokeOperationCommon::init_stroke(const bContext &C,
|
||||
const InputSample &start_sample)
|
||||
{
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
Brush &brush = *BKE_paint_brush(&paint);
|
||||
|
||||
init_brush(brush);
|
||||
|
||||
this->prev_mouse_position = start_sample.mouse_position;
|
||||
}
|
||||
|
||||
void GreasePencilStrokeOperationCommon::stroke_extended(const InputSample &extension_sample)
|
||||
{
|
||||
this->prev_mouse_position = extension_sample.mouse_position;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,233 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_crazyspace.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "BLI_index_mask.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "DNA_grease_pencil_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
class GrabOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
using MutableDrawingInfo = blender::ed::greasepencil::MutableDrawingInfo;
|
||||
using DrawingPlacement = ed::greasepencil::DrawingPlacement;
|
||||
|
||||
/* Cached point mask and influence for a particular drawing. */
|
||||
struct PointWeights {
|
||||
int layer_index;
|
||||
int frame_number;
|
||||
float multi_frame_falloff;
|
||||
|
||||
/* Layer space to view space projection at the start of the stroke. */
|
||||
float4x4 layer_to_win;
|
||||
/* Points that are grabbed at the beginning of the stroke. */
|
||||
IndexMask point_mask;
|
||||
/* Influence weights for grabbed points. */
|
||||
Vector<float> weights;
|
||||
|
||||
IndexMaskMemory memory;
|
||||
};
|
||||
/* Cached point data for each affected drawing. */
|
||||
Array<PointWeights> drawing_data;
|
||||
|
||||
void foreach_grabbed_drawing(const bContext &C,
|
||||
FunctionRef<bool(const GreasePencilStrokeParams ¶ms,
|
||||
const IndexMask &mask,
|
||||
Span<float> weights)> fn) const;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
void GrabOperation::foreach_grabbed_drawing(
|
||||
const bContext &C,
|
||||
FunctionRef<bool(
|
||||
const GreasePencilStrokeParams ¶ms, const IndexMask &mask, Span<float> weights)> fn)
|
||||
const
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
|
||||
const ARegion ®ion = *CTX_wm_region(&C);
|
||||
const View3D &view3d = *CTX_wm_view3d(&C);
|
||||
Object &object = *CTX_data_active_object(&C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
|
||||
|
||||
bool changed = false;
|
||||
threading::parallel_for_each(this->drawing_data.index_range(), [&](const int i) {
|
||||
const PointWeights &data = this->drawing_data[i];
|
||||
if (data.point_mask.is_empty()) {
|
||||
return;
|
||||
}
|
||||
const bke::greasepencil::Layer &layer = *grease_pencil.layers()[data.layer_index];
|
||||
/* If a new frame is created, could be impossible find the stroke. */
|
||||
const int drawing_index = layer.drawing_index_at(data.frame_number);
|
||||
if (drawing_index < 0) {
|
||||
return;
|
||||
}
|
||||
GreasePencilDrawingBase &drawing_base = *grease_pencil.drawing(drawing_index);
|
||||
if (drawing_base.type != GP_DRAWING) {
|
||||
return;
|
||||
}
|
||||
bke::greasepencil::Drawing &drawing =
|
||||
reinterpret_cast<GreasePencilDrawing &>(drawing_base).wrap();
|
||||
|
||||
GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context(
|
||||
scene,
|
||||
depsgraph,
|
||||
region,
|
||||
view3d,
|
||||
object,
|
||||
data.layer_index,
|
||||
data.frame_number,
|
||||
data.multi_frame_falloff,
|
||||
drawing);
|
||||
if (fn(params, data.point_mask, data.weights)) {
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
}
|
||||
}
|
||||
|
||||
void GrabOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
const ARegion ®ion = *CTX_wm_region(&C);
|
||||
const View3D &view3d = *CTX_wm_view3d(&C);
|
||||
const RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
Brush &brush = *BKE_paint_brush(&paint);
|
||||
const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
|
||||
Object &ob_orig = *CTX_data_active_object(&C);
|
||||
Object &ob_eval = *DEG_get_evaluated_object(&depsgraph, &ob_orig);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
|
||||
|
||||
init_brush(brush);
|
||||
|
||||
this->prev_mouse_position = start_sample.mouse_position;
|
||||
|
||||
const Vector<MutableDrawingInfo> drawings = get_drawings_for_sculpt(C);
|
||||
this->drawing_data.reinitialize(drawings.size());
|
||||
threading::parallel_for_each(drawings.index_range(), [&](const int i) {
|
||||
const MutableDrawingInfo &info = drawings[i];
|
||||
BLI_assert(info.layer_index >= 0);
|
||||
PointWeights &data = this->drawing_data[i];
|
||||
|
||||
const bke::greasepencil::Layer &layer = *grease_pencil.layers()[info.layer_index];
|
||||
BLI_assert(layer.drawing_index_at(info.frame_number) >= 0);
|
||||
BLI_assert(grease_pencil.get_drawing_at(layer, info.frame_number) == &info.drawing);
|
||||
|
||||
ed::greasepencil::DrawingPlacement placement(scene, region, view3d, ob_eval, layer);
|
||||
GreasePencilStrokeParams params = {*scene.toolsettings,
|
||||
region,
|
||||
ob_orig,
|
||||
ob_eval,
|
||||
layer,
|
||||
info.layer_index,
|
||||
info.frame_number,
|
||||
info.multi_frame_falloff,
|
||||
std::move(placement),
|
||||
info.drawing};
|
||||
|
||||
IndexMaskMemory selection_memory;
|
||||
IndexMask selection = point_selection_mask(params, selection_memory);
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, selection);
|
||||
|
||||
/* Cache points under brush influence. */
|
||||
Vector<float> weights;
|
||||
IndexMask point_mask = brush_influence_mask(scene,
|
||||
brush,
|
||||
start_sample.mouse_position,
|
||||
start_sample.pressure,
|
||||
info.multi_frame_falloff,
|
||||
selection,
|
||||
view_positions,
|
||||
weights,
|
||||
data.memory);
|
||||
|
||||
if (point_mask.is_empty()) {
|
||||
/* Set empty point mask to skip. */
|
||||
data.point_mask = {};
|
||||
return;
|
||||
}
|
||||
data.layer_index = info.layer_index;
|
||||
data.frame_number = info.frame_number;
|
||||
data.multi_frame_falloff = info.multi_frame_falloff;
|
||||
data.layer_to_win = ED_view3d_ob_project_mat_get(&rv3d, &ob_eval) *
|
||||
layer.to_object_space(ob_eval);
|
||||
data.point_mask = std::move(point_mask);
|
||||
data.weights = std::move(weights);
|
||||
});
|
||||
}
|
||||
|
||||
void GrabOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
|
||||
{
|
||||
const ARegion ®ion = *CTX_wm_region(&C);
|
||||
const RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
|
||||
|
||||
this->foreach_grabbed_drawing(
|
||||
C,
|
||||
[&](const GreasePencilStrokeParams ¶ms,
|
||||
const IndexMask &mask,
|
||||
const Span<float> weights) {
|
||||
/* Crazyspace deformation. */
|
||||
bke::crazyspace::GeometryDeformation deformation = get_drawing_deformation(params);
|
||||
|
||||
/* Transform mouse delta into layer space. */
|
||||
const float2 mouse_delta_win = this->mouse_delta(extension_sample);
|
||||
const float3 layer_origin = params.layer.to_world_space(params.ob_eval).location();
|
||||
const float zfac = ED_view3d_calc_zfac(&rv3d, layer_origin);
|
||||
float3 mouse_delta;
|
||||
ED_view3d_win_to_delta(®ion, mouse_delta_win, zfac, mouse_delta);
|
||||
|
||||
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
mask.foreach_index(GrainSize(1024), [&](const int point_i, const int index) {
|
||||
/* Translate the point with the influence factor. */
|
||||
const float3 new_pos_layer = deformation.positions[point_i] +
|
||||
mouse_delta * weights[index];
|
||||
const float3 new_pos_world = math::transform_point(
|
||||
params.layer.to_world_space(params.ob_eval), new_pos_layer);
|
||||
float2 new_pos_view;
|
||||
ED_view3d_project_float_global(®ion, new_pos_world, new_pos_view, V3D_PROJ_TEST_NOP);
|
||||
positions[point_i] = params.placement.project(new_pos_view);
|
||||
});
|
||||
|
||||
params.drawing.tag_positions_changed();
|
||||
return true;
|
||||
});
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_grab_operation(const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<GrabOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,79 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
class PinchOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
void PinchOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
this->init_stroke(C, start_sample);
|
||||
}
|
||||
|
||||
void PinchOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
const Brush &brush = *BKE_paint_brush(&paint);
|
||||
const bool invert = this->is_inverted(brush);
|
||||
|
||||
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams ¶ms) {
|
||||
IndexMaskMemory selection_memory;
|
||||
const IndexMask selection = point_selection_mask(params, selection_memory);
|
||||
if (selection.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, selection);
|
||||
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
|
||||
const float2 target = extension_sample.mouse_position;
|
||||
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
const float2 &co = view_positions[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, co, extension_sample, params.multi_frame_falloff);
|
||||
if (influence <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float scale_offset = influence * influence / 25.0f;
|
||||
const float scale = invert ? 1.0 + scale_offset : 1.0f - scale_offset;
|
||||
positions[point_i] = params.placement.project(target + (co - target) * scale);
|
||||
});
|
||||
|
||||
params.drawing.tag_positions_changed();
|
||||
return true;
|
||||
});
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_pinch_operation(const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<PinchOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,76 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
class PushOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
void PushOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
this->init_stroke(C, start_sample);
|
||||
}
|
||||
|
||||
void PushOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
const Brush &brush = *BKE_paint_brush(&paint);
|
||||
|
||||
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams ¶ms) {
|
||||
IndexMaskMemory selection_memory;
|
||||
const IndexMask selection = point_selection_mask(params, selection_memory);
|
||||
if (selection.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, selection);
|
||||
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
|
||||
const float2 mouse_delta = this->mouse_delta(extension_sample);
|
||||
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
const float2 &co = view_positions[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, co, extension_sample, params.multi_frame_falloff);
|
||||
if (influence <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
positions[point_i] = params.placement.project(co + mouse_delta * influence);
|
||||
});
|
||||
|
||||
params.drawing.tag_positions_changed();
|
||||
return true;
|
||||
});
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_push_operation(const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<PushOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,153 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_rand.hh"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
/* Use a hash to generate random numbers. */
|
||||
static float hash_rng(uint32_t seed1, uint32_t seed2, int index)
|
||||
{
|
||||
return BLI_hash_int_01(BLI_hash_int_3d(seed1, seed2, uint32_t(index)));
|
||||
}
|
||||
|
||||
class RandomizeOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
|
||||
/* Get a different seed value for each stroke. */
|
||||
uint32_t unique_seed() const;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
uint32_t RandomizeOperation::unique_seed() const
|
||||
{
|
||||
return RandomNumberGenerator::from_random_seed().get_uint32();
|
||||
}
|
||||
|
||||
void RandomizeOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
this->init_stroke(C, start_sample);
|
||||
}
|
||||
|
||||
void RandomizeOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
const Brush &brush = *BKE_paint_brush(&paint);
|
||||
const int sculpt_mode_flag = brush.gpencil_settings->sculpt_mode_flag;
|
||||
|
||||
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams ¶ms) {
|
||||
const uint32_t seed = this->unique_seed();
|
||||
|
||||
IndexMaskMemory selection_memory;
|
||||
const IndexMask selection = point_selection_mask(params, selection_memory);
|
||||
if (selection.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, selection);
|
||||
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
|
||||
bool changed = false;
|
||||
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
|
||||
/* Jitter is applied perpendicular to the mouse movement vector. */
|
||||
const float2 forward = math::normalize(this->mouse_delta(extension_sample));
|
||||
const float2 sideways = float2(-forward.y, forward.x);
|
||||
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
const float2 &co = view_positions[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, co, extension_sample, params.multi_frame_falloff);
|
||||
if (influence <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
const float noise = 2.0f * hash_rng(seed, 5678, point_i) - 1.0f;
|
||||
positions[point_i] = params.placement.project(co + sideways * influence * noise);
|
||||
});
|
||||
|
||||
params.drawing.tag_positions_changed();
|
||||
changed = true;
|
||||
}
|
||||
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
|
||||
MutableSpan<float> opacities = params.drawing.opacities_for_write();
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
const float2 &co = view_positions[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, co, extension_sample, params.multi_frame_falloff);
|
||||
if (influence <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
const float noise = 2.0f * hash_rng(seed, 1212, point_i) - 1.0f;
|
||||
opacities[point_i] = math::clamp(opacities[point_i] + influence * noise, 0.0f, 1.0f);
|
||||
});
|
||||
changed = true;
|
||||
}
|
||||
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
|
||||
const MutableSpan<float> radii = params.drawing.radii_for_write();
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
const float2 &co = view_positions[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, co, extension_sample, params.multi_frame_falloff);
|
||||
if (influence <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
const float noise = 2.0f * hash_rng(seed, 1212, point_i) - 1.0f;
|
||||
radii[point_i] = math::max(radii[point_i] + influence * noise * 0.001f, 0.0f);
|
||||
});
|
||||
curves.tag_radii_changed();
|
||||
changed = true;
|
||||
}
|
||||
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
|
||||
bke::SpanAttributeWriter<float> rotations = attributes.lookup_or_add_for_write_span<float>(
|
||||
"rotation", bke::AttrDomain::Point);
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
const float2 &co = view_positions[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, co, extension_sample, params.multi_frame_falloff);
|
||||
if (influence <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
const float noise = 2.0f * hash_rng(seed, 1212, point_i) - 1.0f;
|
||||
rotations.span[point_i] = math::clamp(
|
||||
rotations.span[point_i] + influence * noise, -float(M_PI_2), float(M_PI_2));
|
||||
});
|
||||
rotations.finish();
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
});
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_randomize_operation(
|
||||
const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<RandomizeOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,140 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "BLI_virtual_array.hh"
|
||||
#include "DNA_brush_enums.h"
|
||||
|
||||
#include "GEO_smooth_curves.hh"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
class SmoothOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
void SmoothOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
this->init_stroke(C, start_sample);
|
||||
}
|
||||
|
||||
void SmoothOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
const Brush &brush = *BKE_paint_brush(&paint);
|
||||
const int sculpt_mode_flag = brush.gpencil_settings->sculpt_mode_flag;
|
||||
|
||||
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams ¶ms) {
|
||||
IndexMaskMemory selection_memory;
|
||||
const IndexMask selection = point_selection_mask(params, selection_memory);
|
||||
if (selection.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, selection);
|
||||
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
const int iterations = 2;
|
||||
|
||||
const VArray<float> influences = VArray<float>::ForFunc(
|
||||
view_positions.size(), [&](const int64_t point_) {
|
||||
return brush_influence(
|
||||
scene, brush, view_positions[point_], extension_sample, params.multi_frame_falloff);
|
||||
});
|
||||
Array<bool> selection_array(curves.points_num());
|
||||
selection.to_bools(selection_array);
|
||||
const VArray<bool> selection_varray = VArray<bool>::ForSpan(selection_array);
|
||||
|
||||
bool changed = false;
|
||||
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
geometry::smooth_curve_attribute(curves.curves_range(),
|
||||
points_by_curve,
|
||||
selection_varray,
|
||||
cyclic,
|
||||
iterations,
|
||||
influences,
|
||||
false,
|
||||
false,
|
||||
positions);
|
||||
params.drawing.tag_positions_changed();
|
||||
changed = true;
|
||||
}
|
||||
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
|
||||
MutableSpan<float> opacities = params.drawing.opacities_for_write();
|
||||
geometry::smooth_curve_attribute(curves.curves_range(),
|
||||
points_by_curve,
|
||||
selection_varray,
|
||||
cyclic,
|
||||
iterations,
|
||||
influences,
|
||||
true,
|
||||
false,
|
||||
opacities);
|
||||
changed = true;
|
||||
}
|
||||
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
|
||||
const MutableSpan<float> radii = params.drawing.radii_for_write();
|
||||
geometry::smooth_curve_attribute(curves.curves_range(),
|
||||
points_by_curve,
|
||||
selection_varray,
|
||||
cyclic,
|
||||
iterations,
|
||||
influences,
|
||||
true,
|
||||
false,
|
||||
radii);
|
||||
curves.tag_radii_changed();
|
||||
changed = true;
|
||||
}
|
||||
if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
|
||||
bke::SpanAttributeWriter<float> rotations = attributes.lookup_or_add_for_write_span<float>(
|
||||
"rotation", bke::AttrDomain::Point);
|
||||
geometry::smooth_curve_attribute(curves.curves_range(),
|
||||
points_by_curve,
|
||||
selection_varray,
|
||||
cyclic,
|
||||
iterations,
|
||||
influences,
|
||||
true,
|
||||
false,
|
||||
rotations.span);
|
||||
rotations.finish();
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
});
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_smooth_operation(
|
||||
const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<SmoothOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,73 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
class StrengthOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
void StrengthOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
this->init_stroke(C, start_sample);
|
||||
}
|
||||
|
||||
void StrengthOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
const Brush &brush = *BKE_paint_brush(&paint);
|
||||
const bool invert = this->is_inverted(brush);
|
||||
|
||||
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams ¶ms) {
|
||||
IndexMaskMemory selection_memory;
|
||||
const IndexMask selection = point_selection_mask(params, selection_memory);
|
||||
if (selection.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, selection);
|
||||
MutableSpan<float> opacities = params.drawing.opacities_for_write();
|
||||
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
float &opacity = opacities[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, view_positions[point_i], extension_sample, params.multi_frame_falloff);
|
||||
/* Brush influence mapped to opacity by a factor of 0.125. */
|
||||
const float delta_opacity = (invert ? -influence : influence) * 0.125f;
|
||||
opacity = std::clamp(opacity + delta_opacity, 0.0f, 1.0f);
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_strength_operation(
|
||||
const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<StrengthOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,77 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_task.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
class ThicknessOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
void ThicknessOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
this->init_stroke(C, start_sample);
|
||||
}
|
||||
|
||||
void ThicknessOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
const Brush &brush = *BKE_paint_brush(&paint);
|
||||
const bool invert = this->is_inverted(brush);
|
||||
|
||||
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams ¶ms) {
|
||||
IndexMaskMemory selection_memory;
|
||||
const IndexMask selection = point_selection_mask(params, selection_memory);
|
||||
if (selection.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, selection);
|
||||
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
|
||||
BLI_assert(view_positions.size() == curves.points_num());
|
||||
MutableSpan<float> radii = params.drawing.radii_for_write();
|
||||
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
float &radius = radii[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, view_positions[point_i], extension_sample, params.multi_frame_falloff);
|
||||
/* Factor 1/1000 is used to map arbitrary influence value to a sensible radius. */
|
||||
const float delta_radius = (invert ? -influence : influence) * 0.001f;
|
||||
radius = std::max(radius + delta_radius, 0.0f);
|
||||
});
|
||||
|
||||
curves.tag_radii_changed();
|
||||
return true;
|
||||
});
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_thickness_operation(
|
||||
const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<ThicknessOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -0,0 +1,86 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_paint.hh"
|
||||
|
||||
#include "ED_grease_pencil.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::greasepencil {
|
||||
|
||||
class TwistOperation : public GreasePencilStrokeOperationCommon {
|
||||
public:
|
||||
using GreasePencilStrokeOperationCommon::GreasePencilStrokeOperationCommon;
|
||||
|
||||
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
|
||||
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
|
||||
void on_stroke_done(const bContext & /*C*/) override {}
|
||||
};
|
||||
|
||||
static float2 rotate_by_angle(const float2 &vec, const float angle)
|
||||
{
|
||||
const float cos_angle = math::cos(angle);
|
||||
const float sin_angle = math::sin(angle);
|
||||
return float2(vec.x * cos_angle - vec.y * sin_angle, vec.x * sin_angle + vec.y * cos_angle);
|
||||
}
|
||||
|
||||
void TwistOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
|
||||
{
|
||||
this->init_stroke(C, start_sample);
|
||||
}
|
||||
|
||||
void TwistOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
|
||||
{
|
||||
const Scene &scene = *CTX_data_scene(&C);
|
||||
Paint &paint = *BKE_paint_get_active_from_context(&C);
|
||||
const Brush &brush = *BKE_paint_brush(&paint);
|
||||
const bool invert = this->is_inverted(brush);
|
||||
|
||||
this->foreach_editable_drawing(C, [&](const GreasePencilStrokeParams ¶ms) {
|
||||
IndexMaskMemory selection_memory;
|
||||
const IndexMask selection = point_selection_mask(params, selection_memory);
|
||||
if (selection.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<float2> view_positions = calculate_view_positions(params, selection);
|
||||
bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
|
||||
const float2 mouse_pos = extension_sample.mouse_position;
|
||||
|
||||
selection.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
|
||||
const float2 &co = view_positions[point_i];
|
||||
const float influence = brush_influence(
|
||||
scene, brush, co, extension_sample, params.multi_frame_falloff);
|
||||
if (influence <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float angle = DEG2RADF(invert ? -1.0f : 1.0f) * influence;
|
||||
positions[point_i] = params.placement.project(rotate_by_angle(co - mouse_pos, angle) +
|
||||
mouse_pos);
|
||||
});
|
||||
|
||||
params.drawing.tag_positions_changed();
|
||||
return true;
|
||||
});
|
||||
this->stroke_extended(extension_sample);
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_twist_operation(const BrushStrokeMode stroke_mode)
|
||||
{
|
||||
return std::make_unique<TwistOperation>(stroke_mode);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::greasepencil
|
|
@ -1215,7 +1215,6 @@ static bool paint_use_2d_cursor(PaintMode mode)
|
|||
return false;
|
||||
case PaintMode::Texture3D:
|
||||
case PaintMode::Texture2D:
|
||||
case PaintMode::SculptUV:
|
||||
case PaintMode::VertexGPencil:
|
||||
case PaintMode::SculptGPencil:
|
||||
case PaintMode::WeightGPencil:
|
||||
|
@ -1686,8 +1685,8 @@ static void paint_cursor_pose_brush_segments_draw(PaintCursorContext *pcontext)
|
|||
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
|
||||
GPU_line_width(2.0f);
|
||||
|
||||
immBegin(GPU_PRIM_LINES, ss->pose_ik_chain_preview->tot_segments * 2);
|
||||
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
|
||||
immBegin(GPU_PRIM_LINES, ss->pose_ik_chain_preview->segments.size() * 2);
|
||||
for (const int i : ss->pose_ik_chain_preview->segments.index_range()) {
|
||||
immVertex3fv(pcontext->pos, ss->pose_ik_chain_preview->segments[i].initial_orig);
|
||||
immVertex3fv(pcontext->pos, ss->pose_ik_chain_preview->segments[i].initial_head);
|
||||
}
|
||||
|
@ -1700,7 +1699,7 @@ static void paint_cursor_pose_brush_origins_draw(PaintCursorContext *pcontext)
|
|||
|
||||
SculptSession *ss = pcontext->ss;
|
||||
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
|
||||
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
|
||||
for (const int i : ss->pose_ik_chain_preview->segments.index_range()) {
|
||||
cursor_draw_point_screen_space(pcontext->pos,
|
||||
pcontext->region,
|
||||
ss->pose_ik_chain_preview->segments[i].initial_orig,
|
||||
|
@ -1813,7 +1812,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
|
|||
|
||||
/* Free the previous pose brush preview. */
|
||||
if (ss->pose_ik_chain_preview) {
|
||||
pose::ik_chain_free(ss->pose_ik_chain_preview);
|
||||
ss->pose_ik_chain_preview.reset();
|
||||
}
|
||||
|
||||
/* Generate a new pose brush preview from the current cursor location. */
|
||||
|
|
|
@ -320,7 +320,9 @@ void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
|
|||
|
||||
/* `sculpt_uv.cc` */
|
||||
|
||||
void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot);
|
||||
void SCULPT_OT_uv_sculpt_grab(wmOperatorType *ot);
|
||||
void SCULPT_OT_uv_sculpt_relax(wmOperatorType *ot);
|
||||
void SCULPT_OT_uv_sculpt_pinch(wmOperatorType *ot);
|
||||
|
||||
/* paint_utils.cc */
|
||||
|
||||
|
|
|
@ -1517,7 +1517,9 @@ void ED_operatortypes_paint()
|
|||
WM_operatortype_append(PAINT_OT_weight_sample_group);
|
||||
|
||||
/* uv */
|
||||
WM_operatortype_append(SCULPT_OT_uv_sculpt_stroke);
|
||||
WM_operatortype_append(SCULPT_OT_uv_sculpt_grab);
|
||||
WM_operatortype_append(SCULPT_OT_uv_sculpt_relax);
|
||||
WM_operatortype_append(SCULPT_OT_uv_sculpt_pinch);
|
||||
|
||||
/* vertex selection */
|
||||
WM_operatortype_append(PAINT_OT_vert_select_all);
|
||||
|
|
|
@ -1699,8 +1699,19 @@ static void vpaint_do_draw(bContext *C,
|
|||
float tex_alpha = 1.0;
|
||||
if (vpd->is_texbrush) {
|
||||
/* NOTE: we may want to paint alpha as vertex color alpha. */
|
||||
tex_alpha = paint_and_tex_color_alpha<Color>(
|
||||
vp, vpd, vpd->vertexcosnos[v_index].co, &color_final);
|
||||
|
||||
/* If the active area is being applied for symmetry, flip it
|
||||
* across the symmetry axis and rotate it back to the original
|
||||
* position in order to project it. This insures that the
|
||||
* brush texture will be oriented correctly.
|
||||
* This is the method also used in #sculpt_apply_texture(). */
|
||||
float symm_point[3];
|
||||
if (cache->radial_symmetry_pass) {
|
||||
mul_m4_v3(cache->symm_rot_mat_inv.ptr(), vpd->vertexcosnos[v_index].co);
|
||||
}
|
||||
flip_v3_v3(symm_point, vpd->vertexcosnos[v_index].co, cache->mirror_symmetry_pass);
|
||||
|
||||
tex_alpha = paint_and_tex_color_alpha<Color>(vp, vpd, symm_point, &color_final);
|
||||
}
|
||||
|
||||
Color color_orig(0, 0, 0, 0);
|
||||
|
@ -1853,8 +1864,7 @@ static void vpaint_do_radial_symmetry(bContext *C,
|
|||
}
|
||||
}
|
||||
|
||||
/* near duplicate of: sculpt.cc's,
|
||||
* 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
|
||||
/* near duplicate of: #do_symmetrical_brush_actions and #wpaint_do_symmetrical_brush_actions. */
|
||||
static void vpaint_do_symmetrical_brush_actions(bContext *C,
|
||||
VPaint *vp,
|
||||
VPaintData *vpd,
|
||||
|
@ -1865,40 +1875,26 @@ static void vpaint_do_symmetrical_brush_actions(bContext *C,
|
|||
SculptSession *ss = ob->sculpt;
|
||||
StrokeCache *cache = ss->cache;
|
||||
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
||||
int i = 0;
|
||||
|
||||
/* initial stroke */
|
||||
const ePaintSymmetryFlags initial_symm = ePaintSymmetryFlags(0);
|
||||
cache->mirror_symmetry_pass = ePaintSymmetryFlags(0);
|
||||
vpaint_do_paint(C, vp, vpd, ob, mesh, brush, initial_symm, 'X', 0, 0);
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'X');
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'Y');
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'Z');
|
||||
|
||||
cache->symmetry = symm;
|
||||
|
||||
/* symm is a bit combination of XYZ - 1 is mirror
|
||||
* X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
|
||||
for (i = 1; i <= symm; i++) {
|
||||
if (symm & i && (symm != 5 || i != 3) && (symm != 6 || !ELEM(i, 3, 5))) {
|
||||
const ePaintSymmetryFlags symm_pass = ePaintSymmetryFlags(i);
|
||||
cache->mirror_symmetry_pass = symm_pass;
|
||||
cache->radial_symmetry_pass = 0;
|
||||
SCULPT_cache_calc_brushdata_symm(cache, symm_pass, 0, 0);
|
||||
/* symm is a bit combination of XYZ -
|
||||
* 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
|
||||
for (int i = 0; i <= symm; i++) {
|
||||
|
||||
if (i & (1 << 0)) {
|
||||
vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'X', 0, 0);
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'X');
|
||||
}
|
||||
if (i & (1 << 1)) {
|
||||
vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y', 0, 0);
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y');
|
||||
}
|
||||
if (i & (1 << 2)) {
|
||||
vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z', 0, 0);
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z');
|
||||
}
|
||||
if (!SCULPT_is_symmetry_iteration_valid(i, symm)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ePaintSymmetryFlags symm_pass = ePaintSymmetryFlags(i);
|
||||
cache->mirror_symmetry_pass = symm_pass;
|
||||
cache->radial_symmetry_pass = 0;
|
||||
SCULPT_cache_calc_brushdata_symm(cache, symm_pass, 0, 0);
|
||||
|
||||
vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'X', 0, 0);
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'X');
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y');
|
||||
vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z');
|
||||
}
|
||||
|
||||
copy_v3_v3(cache->true_last_location, cache->true_location);
|
||||
|
|
|
@ -1726,8 +1726,7 @@ static void wpaint_do_radial_symmetry(bContext *C,
|
|||
}
|
||||
}
|
||||
|
||||
/* near duplicate of: sculpt.cc's,
|
||||
* 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */
|
||||
/* near duplicate of: #do_symmetrical_brush_actions and #vpaint_do_symmetrical_brush_actions. */
|
||||
static void wpaint_do_symmetrical_brush_actions(
|
||||
bContext *C, Object *ob, VPaint *wp, WPaintData *wpd, WeightPaintInfo *wpi)
|
||||
{
|
||||
|
@ -1736,14 +1735,6 @@ static void wpaint_do_symmetrical_brush_actions(
|
|||
SculptSession *ss = ob->sculpt;
|
||||
StrokeCache *cache = ss->cache;
|
||||
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
||||
int i = 0;
|
||||
|
||||
/* initial stroke */
|
||||
cache->mirror_symmetry_pass = ePaintSymmetryFlags(0);
|
||||
wpaint_do_paint(C, ob, wp, wpd, wpi, mesh, brush, ePaintSymmetryFlags(0), 'X', 0, 0);
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, ePaintSymmetryFlags(0), 'X');
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, ePaintSymmetryFlags(0), 'Y');
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, ePaintSymmetryFlags(0), 'Z');
|
||||
|
||||
cache->symmetry = symm;
|
||||
|
||||
|
@ -1754,28 +1745,22 @@ static void wpaint_do_symmetrical_brush_actions(
|
|||
return;
|
||||
}
|
||||
|
||||
/* symm is a bit combination of XYZ - 1 is mirror
|
||||
* X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
|
||||
for (i = 1; i <= symm; i++) {
|
||||
if (symm & i && (symm != 5 || i != 3) && (symm != 6 || !ELEM(i, 3, 5))) {
|
||||
const ePaintSymmetryFlags symm = ePaintSymmetryFlags(i);
|
||||
cache->mirror_symmetry_pass = symm;
|
||||
cache->radial_symmetry_pass = 0;
|
||||
SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0);
|
||||
|
||||
if (i & (1 << 0)) {
|
||||
wpaint_do_paint(C, ob, wp, wpd, wpi, mesh, brush, symm, 'X', 0, 0);
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, symm, 'X');
|
||||
}
|
||||
if (i & (1 << 1)) {
|
||||
wpaint_do_paint(C, ob, wp, wpd, wpi, mesh, brush, symm, 'Y', 0, 0);
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, symm, 'Y');
|
||||
}
|
||||
if (i & (1 << 2)) {
|
||||
wpaint_do_paint(C, ob, wp, wpd, wpi, mesh, brush, symm, 'Z', 0, 0);
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, symm, 'Z');
|
||||
}
|
||||
/* symm is a bit combination of XYZ -
|
||||
* 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
|
||||
for (int i = 0; i <= symm; i++) {
|
||||
if (!SCULPT_is_symmetry_iteration_valid(i, symm)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ePaintSymmetryFlags symm = ePaintSymmetryFlags(i);
|
||||
cache->mirror_symmetry_pass = symm;
|
||||
cache->radial_symmetry_pass = 0;
|
||||
SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0);
|
||||
|
||||
wpaint_do_paint(C, ob, wp, wpd, wpi, mesh, brush, symm, 'X', 0, 0);
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, symm, 'X');
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, symm, 'Y');
|
||||
wpaint_do_radial_symmetry(C, ob, wp, wpd, wpi, mesh, brush, symm, 'Z');
|
||||
}
|
||||
copy_v3_v3(cache->true_last_location, cache->true_location);
|
||||
cache->is_last_valid = true;
|
||||
|
|
|
@ -379,7 +379,7 @@ namespace blender::ed::sculpt_paint {
|
|||
|
||||
namespace face_set {
|
||||
|
||||
int active_face_set_get(SculptSession *ss)
|
||||
int active_face_set_get(const SculptSession *ss)
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES:
|
||||
|
@ -429,7 +429,7 @@ bool vert_visible_get(const SculptSession *ss, PBVHVertRef vertex)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool vert_any_face_visible_get(SculptSession *ss, PBVHVertRef vertex)
|
||||
bool vert_any_face_visible_get(const SculptSession *ss, PBVHVertRef vertex)
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
|
@ -506,7 +506,7 @@ bool vert_all_faces_visible_get(const SculptSession *ss, PBVHVertRef vertex)
|
|||
|
||||
namespace face_set {
|
||||
|
||||
int vert_face_set_get(SculptSession *ss, PBVHVertRef vertex)
|
||||
int vert_face_set_get(const SculptSession *ss, PBVHVertRef vertex)
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
|
@ -536,7 +536,7 @@ int vert_face_set_get(SculptSession *ss, PBVHVertRef vertex)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool vert_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set)
|
||||
bool vert_has_face_set(const SculptSession *ss, PBVHVertRef vertex, int face_set)
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
|
@ -565,7 +565,7 @@ bool vert_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_set)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index)
|
||||
static bool sculpt_check_unique_face_set_in_base_mesh(const SculptSession *ss, int index)
|
||||
{
|
||||
if (!ss->face_sets) {
|
||||
return true;
|
||||
|
@ -588,7 +588,9 @@ static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int ind
|
|||
* Checks if the face sets of the adjacent faces to the edge between \a v1 and \a v2
|
||||
* in the base mesh are equal.
|
||||
*/
|
||||
static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss, int v1, int v2)
|
||||
static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(const SculptSession *ss,
|
||||
int v1,
|
||||
int v2)
|
||||
{
|
||||
const Span<int> vert_map = ss->vert_to_face_map[v1];
|
||||
int p1 = -1, p2 = -1;
|
||||
|
@ -615,7 +617,7 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss
|
|||
return true;
|
||||
}
|
||||
|
||||
bool vert_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex)
|
||||
bool vert_has_unique_face_set(const SculptSession *ss, PBVHVertRef vertex)
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
|
@ -718,7 +720,7 @@ static void sculpt_vertex_neighbors_get_bmesh(PBVHVertRef vertex, SculptVertexNe
|
|||
}
|
||||
}
|
||||
|
||||
static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
|
||||
static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
|
||||
PBVHVertRef vertex,
|
||||
SculptVertexNeighborIter *iter)
|
||||
{
|
||||
|
@ -753,7 +755,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
|
|||
}
|
||||
}
|
||||
|
||||
static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
|
||||
static void sculpt_vertex_neighbors_get_grids(const SculptSession *ss,
|
||||
const PBVHVertRef vertex,
|
||||
const bool include_duplicates,
|
||||
SculptVertexNeighborIter *iter)
|
||||
|
@ -797,7 +799,7 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
|
|||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
|
||||
void SCULPT_vertex_neighbors_get(SculptSession *ss,
|
||||
void SCULPT_vertex_neighbors_get(const SculptSession *ss,
|
||||
const PBVHVertRef vertex,
|
||||
const bool include_duplicates,
|
||||
SculptVertexNeighborIter *iter)
|
||||
|
@ -1008,10 +1010,12 @@ namespace blender::ed::sculpt_paint {
|
|||
|
||||
namespace flood_fill {
|
||||
|
||||
void init_fill(SculptSession *ss, FillData *flood)
|
||||
FillData init_fill(SculptSession *ss)
|
||||
{
|
||||
SCULPT_vertex_random_access_ensure(ss);
|
||||
flood->visited_verts.resize(SCULPT_vertex_count_get(ss));
|
||||
FillData data;
|
||||
data.visited_verts.resize(SCULPT_vertex_count_get(ss));
|
||||
return data;
|
||||
}
|
||||
|
||||
void add_initial(FillData *flood, PBVHVertRef vertex)
|
||||
|
@ -1078,11 +1082,9 @@ void add_active(Object *ob, SculptSession *ss, FillData *flood, float radius)
|
|||
}
|
||||
}
|
||||
|
||||
void execute(
|
||||
SculptSession *ss,
|
||||
FillData *flood,
|
||||
FunctionRef<bool(SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate)>
|
||||
func)
|
||||
void execute(SculptSession *ss,
|
||||
FillData *flood,
|
||||
FunctionRef<bool(PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate)> func)
|
||||
{
|
||||
while (!flood->queue.empty()) {
|
||||
PBVHVertRef from_v = flood->queue.front();
|
||||
|
@ -1103,7 +1105,7 @@ void execute(
|
|||
|
||||
flood->visited_verts[BKE_pbvh_vertex_to_index(ss->pbvh, to_v)].set();
|
||||
|
||||
if (func(ss, from_v, to_v, ni.is_duplicate)) {
|
||||
if (func(from_v, to_v, ni.is_duplicate)) {
|
||||
flood->queue.push(to_v);
|
||||
}
|
||||
}
|
||||
|
@ -3999,6 +4001,8 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
|
|||
}
|
||||
}
|
||||
|
||||
/* near duplicate of: #wpaint_do_symmetrical_brush_actions and
|
||||
* #vpaint_do_symmetrical_brush_actions. */
|
||||
static void do_symmetrical_brush_actions(Sculpt *sd,
|
||||
Object *ob,
|
||||
BrushActionFunc action,
|
||||
|
@ -4142,10 +4146,6 @@ void SCULPT_cache_free(blender::ed::sculpt_paint::StrokeCache *cache)
|
|||
MEM_SAFE_FREE(cache->prev_displacement);
|
||||
MEM_SAFE_FREE(cache->limit_surface_co);
|
||||
|
||||
if (cache->pose_ik_chain) {
|
||||
pose::ik_chain_free(cache->pose_ik_chain);
|
||||
}
|
||||
|
||||
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
|
||||
if (cache->boundaries[i]) {
|
||||
boundary::data_free(cache->boundaries[i]);
|
||||
|
|
|
@ -626,8 +626,7 @@ static void topology_automasking_init(const Sculpt *sd, Object *ob)
|
|||
|
||||
/* Flood fill automask to connected vertices. Limited to vertices inside
|
||||
* the brush radius if the tool requires it. */
|
||||
flood_fill::FillData flood;
|
||||
flood_fill::init_fill(ss, &flood);
|
||||
flood_fill::FillData flood = flood_fill::init_fill(ss);
|
||||
const float radius = ss->cache ? ss->cache->radius : FLT_MAX;
|
||||
flood_fill::add_active(ob, ss, &flood, radius);
|
||||
|
||||
|
@ -639,9 +638,7 @@ static void topology_automasking_init(const Sculpt *sd, Object *ob)
|
|||
|
||||
copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
|
||||
flood_fill::execute(
|
||||
ss,
|
||||
&flood,
|
||||
[&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool /*is_duplicate*/) {
|
||||
ss, &flood, [&](PBVHVertRef from_v, PBVHVertRef to_v, bool /*is_duplicate*/) {
|
||||
return floodfill_cb(ss, from_v, to_v, &fdata);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -87,8 +87,7 @@ static PBVHVertRef sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss
|
|||
return initial_vertex;
|
||||
}
|
||||
|
||||
flood_fill::FillData flood;
|
||||
flood_fill::init_fill(ss, &flood);
|
||||
flood_fill::FillData flood = flood_fill::init_fill(ss);
|
||||
flood_fill::add_initial(&flood, initial_vertex);
|
||||
|
||||
BoundaryInitialVertexFloodFillData fdata{};
|
||||
|
@ -99,10 +98,9 @@ static PBVHVertRef sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss
|
|||
|
||||
fdata.floodfill_steps = MEM_cnew_array<int>(SCULPT_vertex_count_get(ss), __func__);
|
||||
|
||||
flood_fill::execute(
|
||||
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
|
||||
return boundary_initial_vertex_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
|
||||
});
|
||||
flood_fill::execute(ss, &flood, [&](PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
|
||||
return boundary_initial_vertex_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
|
||||
});
|
||||
|
||||
MEM_freeN(fdata.floodfill_steps);
|
||||
return fdata.boundary_initial_vertex;
|
||||
|
@ -247,8 +245,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
|
|||
MEM_malloc_arrayN(BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptBoundaryPreviewEdge), __func__));
|
||||
|
||||
GSet *included_verts = BLI_gset_int_new_ex("included verts", BOUNDARY_INDICES_BLOCK_SIZE);
|
||||
flood_fill::FillData flood;
|
||||
flood_fill::init_fill(ss, &flood);
|
||||
flood_fill::FillData flood = flood_fill::init_fill(ss);
|
||||
|
||||
int initial_boundary_index = BKE_pbvh_vertex_to_index(ss->pbvh, initial_boundary_vertex);
|
||||
|
||||
|
@ -266,10 +263,9 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
|
|||
fdata.included_verts = included_verts;
|
||||
fdata.last_visited_vertex = {BOUNDARY_VERTEX_NONE};
|
||||
|
||||
flood_fill::execute(
|
||||
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
|
||||
return boundary_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
|
||||
});
|
||||
flood_fill::execute(ss, &flood, [&](PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
|
||||
return boundary_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
|
||||
});
|
||||
|
||||
/* Check if the boundary loops into itself and add the extra preview edge to close the loop. */
|
||||
if (fdata.last_visited_vertex.i != BOUNDARY_VERTEX_NONE &&
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue