Compare commits
403 Commits
temp-move-
...
temp_bmesh
Author | SHA1 | Date | |
---|---|---|---|
f0c35d16f3 | |||
d3bba94bf2 | |||
04c3690299 | |||
627edd1efa | |||
445889676b | |||
350e783668 | |||
0b2aee5841 | |||
ecdd6a302e | |||
173f5f94ff | |||
0eeaeb3fc2 | |||
3df335d330 | |||
0676928408 | |||
e68667a835 | |||
86972d294f | |||
f52a03dd71 | |||
a52f89a446 | |||
9f3bafc4ab | |||
bb1096f475 | |||
3e6edf5278 | |||
37bce7b701 | |||
6febbd7a55 | |||
416c7a32d8 | |||
d4badd4b22 | |||
4e43e09cca | |||
21b6d78cd2 | |||
2b20931707 | |||
416686707f | |||
8bfbbc467a | |||
baa24243a5 | |||
73529fb1bb | |||
381ef09073 | |||
56ba339cd8 | |||
055fa3fa5e | |||
7d5c3beb06 | |||
39b0e9df81 | |||
b21595cdf9 | |||
e4b36fb6bc | |||
966e4ba9ae | |||
268682527f | |||
cdb52aee9f | |||
8b02ab86f1 | |||
019700583b | |||
31d2b04411 | |||
3508c699fb | |||
8ea7c93a37 | |||
12f87d02c6 | |||
9680edf77c | |||
a00bfa8976 | |||
bde54e127e | |||
9b8c82e2ed | |||
5866a4680d | |||
d795144f54 | |||
de6258c618 | |||
d912ceeb40 | |||
9a197a1185 | |||
36785c83f0 | |||
8eb7a04150 | |||
97c3e5944c | |||
6f523ffacb | |||
04562794df | |||
93004c7b19 | |||
0d542db1e1 | |||
de1f2c41fa | |||
106f542ac4 | |||
83f94ebb6f | |||
954aa88ba4 | |||
9503751c83 | |||
dcaba4c5e3 | |||
fb463a13cd | |||
b5100e73c8 | |||
ab632243e6 | |||
8510c77b9c | |||
40aa321dc7 | |||
a80c381ec5 | |||
1e9a7383ef | |||
dc738de90c | |||
8ed4c5fc61 | |||
76bd253be7 | |||
b243eb2646 | |||
af71984942 | |||
ec4b9dff19 | |||
70a4956020 | |||
7cd74015f8 | |||
7bd521a5c4 | |||
7dda5ac5ba | |||
1694e2aca4 | |||
2fddbebf93 | |||
4247a56cde | |||
e3b58b6451 | |||
5b10d08db3 | |||
7c4eb4f8db | |||
792292e3de | |||
4ca249018d | |||
d529e13d65 | |||
4e797dbc69 | |||
1b9a835893 | |||
320a1b6f35 | |||
f07f56aa37 | |||
4e91e72d53 | |||
58b4688c34 | |||
2f862bc7b9 | |||
4674795591 | |||
be9017c349 | |||
4c2f5b80b7 | |||
0502b0103f | |||
e8b717ee42 | |||
4b4ac93acd | |||
57286eed8d | |||
d0759840a0 | |||
5b19b2cb56 | |||
dcb00bf529 | |||
d66d5b431e | |||
43a0fe378f | |||
fb6636c812 | |||
adc8980dec | |||
48c41b189a | |||
7562ad5777 | |||
27986e9b56 | |||
dba4f30328 | |||
83c491f044 | |||
7ef7843ada | |||
5a7b9adef1 | |||
d293de425f | |||
17d4c7abb1 | |||
ca4ac36c59 | |||
00fd823bcd | |||
8ca52a7757 | |||
4adc0a7798 | |||
552e44bd25 | |||
1f19a86150 | |||
3ca3098ed7 | |||
995702da48 | |||
33066542ca | |||
5a26ea0961 | |||
1e3e79fe7b | |||
d4292bbd28 | |||
a97c5d7daa | |||
6b009b8890 | |||
3d16099a77 | |||
4352980b0f | |||
3d6ac0bd7b | |||
71959181ad | |||
daa4a33383 | |||
d3695eb12c | |||
c1f236dcd4 | |||
a90533e9b8 | |||
9bea7259e1 | |||
7fca310f25 | |||
27f4f761e7 | |||
17fafe2f63 | |||
89d56ea225 | |||
cfd6d48aab | |||
6be2c079c1 | |||
32ceaa7919 | |||
ec4786d00b | |||
582c30d32f | |||
b047b333b0 | |||
f2c9706781 | |||
fa06238aa7 | |||
b8a8e4f9b1 | |||
dbe767f5d9 | |||
7cf3b1f472 | |||
6c3b29a14c | |||
febfaecd97 | |||
2d98802905 | |||
f70a8c1581 | |||
8eeacca9cb | |||
82847af9f9 | |||
ee19a80041 | |||
013eee7ec6 | |||
83a855a8a1 | |||
9e46eebcf1 | |||
786781304c | |||
3028d53865 | |||
02b4df9827 | |||
815d77192f | |||
9fab16f0f3 | |||
82f5e0200c | |||
032a35fb50 | |||
8a700673db | |||
0386350de6 | |||
97fc606c65 | |||
14be52f0fc | |||
73c590e1eb | |||
fdc6fb2c53 | |||
237ac342c9 | |||
465e804193 | |||
4ab8614cd1 | |||
dabff9af7d | |||
384a0930d1 | |||
a5fa9ec310 | |||
ed15d0c1b9 | |||
e07a95b86d | |||
b52e04f794 | |||
e74c298cf9 | |||
cd485a7c6f | |||
06341c19c4 | |||
a527bd5f48 | |||
7f14d519c0 | |||
64337d087d | |||
e1fae3cbee | |||
7dbb4c9b2d | |||
fe67ca56d6 | |||
881df30a46 | |||
6f91eaad39 | |||
55045ed85a | |||
2582090824 | |||
55415cd62a | |||
8aac19cab5 | |||
b4536d274c | |||
f5588dfb70 | |||
4b308888d8 | |||
fdfa2045ec | |||
33af94dc46 | |||
8ea624aeaf | |||
e29cd298fe | |||
7bba304c57 | |||
0dc09668ce | |||
cfa6753518 | |||
2cf8c35578 | |||
aa116ba5ba | |||
7be027075f | |||
215c346017 | |||
7c9235d0e0 | |||
e254cc23b2 | |||
dee286fc7e | |||
ab9b89ac5d | |||
924b13b03a | |||
75a1116b51 | |||
f6cda6bf88 | |||
cb0f159155 | |||
8a98189bfb | |||
1f2b48eb45 | |||
148b39caec | |||
e9f9217f75 | |||
dd45a4bc6e | |||
1ccd92d0bb | |||
1a17c578a8 | |||
56e1ae1afa | |||
35092510ba | |||
5385455e6a | |||
2c54c641a3 | |||
b3fff9b07a | |||
681e2b6134 | |||
49bd2228cb | |||
0a140ec66e | |||
f30225725d | |||
a1ac104f02 | |||
d823f6e2cf | |||
3042f6e608 | |||
6115091103 | |||
78ef2d0d84 | |||
9d92a97562 | |||
192670e8ce | |||
7ae1cc23fc | |||
ebb6648bda | |||
384f2956e5 | |||
2ba90cf717 | |||
e5af8597e5 | |||
1f6a7785f6 | |||
0ee053fb12 | |||
8cd4776764 | |||
f32bde6bd9 | |||
![]() |
8b808cefae | ||
f8466b6284 | |||
4a2d7a2f89 | |||
67defe866b | |||
b6575fed92 | |||
d6735bfae0 | |||
e4c45d0c5e | |||
c4668b750c | |||
81a85233a7 | |||
89f62e5dc3 | |||
408e13783d | |||
3900734063 | |||
fa688ac593 | |||
787f952ef4 | |||
63241d25b9 | |||
![]() |
98166b5c98 | ||
229849af0f | |||
0a1fc855bc | |||
46ccaff9a3 | |||
9c8b0a20c1 | |||
a42cf75ecb | |||
d77e884bd7 | |||
e2111233f0 | |||
e4efd04063 | |||
8edd20274e | |||
9be60839cd | |||
af934d751d | |||
5ac07c31f0 | |||
f3a7d9375d | |||
a033a0eaaf | |||
c137b53569 | |||
f0a9986ccf | |||
f639ffe795 | |||
326381bfe1 | |||
174e3c6b65 | |||
5c899dcc92 | |||
24ee80f077 | |||
22b69af796 | |||
0758c006ec | |||
c2a329ec07 | |||
bdaee543f3 | |||
44d358c384 | |||
f87123a6eb | |||
f2fc2cd521 | |||
af92a39e37 | |||
49cbb23855 | |||
9cb84de509 | |||
53f6991de8 | |||
5b696c2bd8 | |||
b95a5c2e68 | |||
080e78d205 | |||
a55a69f81a | |||
596fea8afd | |||
47e4adde5a | |||
a349943cd7 | |||
360faf5c3c | |||
9cf97857d1 | |||
44bdf515ba | |||
45ccdebad3 | |||
d242d33571 | |||
731eaa68d3 | |||
344963bf23 | |||
aaca5731fb | |||
aa7147f665 | |||
0fb50afdc5 | |||
f3cc74d216 | |||
0946a8da3b | |||
a8e5e63f45 | |||
e52f8ac7ce | |||
71a088582a | |||
3aab8dd731 | |||
56d57b2e9d | |||
b16eb9d7ad | |||
3fcd3d41c4 | |||
0b0bfa0628 | |||
ff9ce5fd98 | |||
2d99e118b4 | |||
a93add61b0 | |||
7f28a99dd5 | |||
9aaf9857a0 | |||
e2595de761 | |||
40c4942901 | |||
2e188dc504 | |||
![]() |
dfce29b809 | ||
decf7adcf6 | |||
81531d5e76 | |||
15bc0b7d5d | |||
17dec471c5 | |||
81f05aca29 | |||
d1270925a5 | |||
9e09ae7aff | |||
![]() |
c51a5e1066 | ||
758452ffba | |||
c7cd82c356 | |||
cc554eea75 | |||
0d770432d6 | |||
b2cb9d4b1b | |||
08e19c6bc0 | |||
b928f58849 | |||
228c1e5345 | |||
488af21ae0 | |||
b54d7bfad8 | |||
2babf80ae6 | |||
022dcb8e6c | |||
6d66e81667 | |||
91a5e1aef8 | |||
6d704d57ad | |||
a1b1c840a0 | |||
901654dcbf | |||
37a657a45f | |||
e07bb3955e | |||
7834b59598 | |||
0c8d40d2de | |||
1014b6f455 | |||
093e29f3c2 | |||
0f0d1f8e2a | |||
43ccbe353f | |||
2d861122e1 | |||
66f8852e30 | |||
54ddb01299 | |||
3d47323162 | |||
5c77439264 | |||
e2c92c1341 | |||
faf8402c19 | |||
4c0bcc3d13 | |||
4fc4a7e1f4 | |||
f9859a3b2a | |||
6da9fa1bf2 | |||
5c6407c268 | |||
3214b1114f | |||
bfbe9a0d55 | |||
f482afadab | |||
661dcd813c | |||
5541de9a3a | |||
3791afa29c | |||
3ae8229843 | |||
f61d4b2e3a | |||
49f57d8de8 | |||
64c7bad391 | |||
4659855b0f |
@@ -263,6 +263,7 @@ ForEachMacros:
|
||||
- SET_SLOT_PROBING_BEGIN
|
||||
- MAP_SLOT_PROBING_BEGIN
|
||||
- VECTOR_SET_SLOT_PROBING_BEGIN
|
||||
- TGSET_ITER
|
||||
|
||||
StatementMacros:
|
||||
- PyObject_HEAD
|
||||
|
@@ -578,6 +578,12 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/7.0.0/lib/windows
|
||||
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/6.0.0/lib/windows
|
||||
)
|
||||
find_library(
|
||||
COMPILER_ASAN_LIBRARY_THUNK NAMES clang_rt.asan_dll_thunk-x86_64
|
||||
PATHS
|
||||
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/7.0.0/lib/windows
|
||||
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/6.0.0/lib/windows
|
||||
)
|
||||
elseif(APPLE)
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER}
|
||||
-print-file-name=lib
|
||||
@@ -598,6 +604,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(COMPILER_ASAN_LIBRARY_THUNK)
|
||||
mark_as_advanced(COMPILER_ASAN_LIBRARY)
|
||||
endif()
|
||||
endif()
|
||||
@@ -918,9 +925,9 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Release")
|
||||
unset(_list_COMPILER_ASAN_CFLAGS)
|
||||
unset(_is_CONFIG_DEBUG)
|
||||
elseif(COMPILER_ASAN_LIBRARY)
|
||||
set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}")
|
||||
set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
|
||||
set(PLATFORM_LINKFLAGS_DEBUG "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
|
||||
set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\"")
|
||||
set(PLATFORM_LINKFLAGS "\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\" ${COMPILER_ASAN_LINKER_FLAGS}")
|
||||
set(PLATFORM_LINKFLAGS_DEBUG "\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\" ${COMPILER_ASAN_LINKER_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
2
extern/Eigen3/Eigen/src/Core/util/Macros.h
vendored
2
extern/Eigen3/Eigen/src/Core/util/Macros.h
vendored
@@ -389,7 +389,7 @@
|
||||
|
||||
// Does the compiler support result_of?
|
||||
#ifndef EIGEN_HAS_STD_RESULT_OF
|
||||
#if EIGEN_MAX_CPP_VER>=11 && ((__has_feature(cxx_lambdas) || (defined(__cplusplus) && __cplusplus >= 201103L)))
|
||||
#if __cplusplus < 201703L && EIGEN_MAX_CPP_VER>=11 && ((__has_feature(cxx_lambdas) || (defined(__cplusplus) && __cplusplus >= 201103L && __cplusplus)))
|
||||
#define EIGEN_HAS_STD_RESULT_OF 1
|
||||
#else
|
||||
#define EIGEN_HAS_STD_RESULT_OF 0
|
||||
|
2
extern/audaspace/bindings/C/AUD_Device.cpp
vendored
2
extern/audaspace/bindings/C/AUD_Device.cpp
vendored
@@ -221,7 +221,7 @@ AUD_API void AUD_Device_setListenerVelocity(AUD_Device* device, const float valu
|
||||
AUD_API double AUD_Device_getRate(AUD_Device* device)
|
||||
{
|
||||
auto dev = device ? *device : DeviceManager::getDevice();
|
||||
return dev->getSpecs().rate;
|
||||
return dev ? dev->getSpecs().rate : 0.0;
|
||||
}
|
||||
|
||||
AUD_API float AUD_Device_getSpeedOfSound(AUD_Device* device)
|
||||
|
8
extern/audaspace/include/util/ThreadPool.h
vendored
8
extern/audaspace/include/util/ThreadPool.h
vendored
@@ -87,11 +87,17 @@ public:
|
||||
* \param args The arguments of the task.
|
||||
* \return A future of the same type as the return type of the task.
|
||||
*/
|
||||
#if __cplusplus > 201703L
|
||||
template<class T, class... Args>
|
||||
std::future<typename std::invoke_result<T, Args...>::type> enqueue(T&& t, Args&&... args)
|
||||
{
|
||||
using pkgdTask = std::packaged_task<typename std::invoke_result<T, Args...>::type()>;
|
||||
#else
|
||||
template<class T, class... Args>
|
||||
std::future<typename std::result_of<T(Args...)>::type> enqueue(T&& t, Args&&... args)
|
||||
{
|
||||
using pkgdTask = std::packaged_task<typename std::result_of<T(Args...)>::type()>;
|
||||
|
||||
#endif
|
||||
std::shared_ptr<pkgdTask> task = std::make_shared<pkgdTask>(std::bind(std::forward<T>(t), std::forward<Args>(args)...));
|
||||
auto result = task->get_future();
|
||||
|
||||
|
@@ -67,7 +67,7 @@ SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.")
|
||||
SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.")
|
||||
SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.")
|
||||
|
||||
IF(LEMON_ENABLE_GLPK)
|
||||
IF(LEMON_ENABLE_GLPK)
|
||||
FIND_PACKAGE(GLPK 4.33)
|
||||
ENDIF(LEMON_ENABLE_GLPK)
|
||||
IF(LEMON_ENABLE_ILOG)
|
||||
|
@@ -4,7 +4,7 @@ FIND_PATH(ILOG_ROOT_DIR
|
||||
PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog
|
||||
PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG"
|
||||
PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG"
|
||||
PATHS "C:/Program Files/IBM/ILOG"
|
||||
PATHS "C:/Program Files/IBM/ILOG"
|
||||
PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125"
|
||||
"CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122"
|
||||
NO_DEFAULT_PATH
|
||||
|
@@ -16,3 +16,4 @@ LINK_DIRECTORIES(
|
||||
|
||||
# ADD_EXECUTABLE(myprog myprog-main.cc)
|
||||
# TARGET_LINK_LIBRARIES(myprog lemon)
|
||||
|
||||
|
@@ -88,3 +88,4 @@ INSTALL(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc
|
||||
DESTINATION lib/pkgconfig
|
||||
)
|
||||
|
||||
|
3
extern/quadriflow/src/loader.cpp
vendored
3
extern/quadriflow/src/loader.cpp
vendored
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
namespace qflow {
|
||||
|
||||
@@ -69,7 +70,7 @@ void load(const char* filename, MatrixXd& V, MatrixXi& F)
|
||||
};
|
||||
|
||||
/// Hash function for obj_vertex
|
||||
struct obj_vertexHash {
|
||||
struct obj_vertexHash : std::function<size_t(obj_vertex)> {
|
||||
std::size_t operator()(const obj_vertex &v) const {
|
||||
size_t hash = std::hash<uint32_t>()(v.p);
|
||||
hash = hash * 37 + std::hash<uint32_t>()(v.uv);
|
||||
|
@@ -49,27 +49,27 @@
|
||||
/* Unsigned */
|
||||
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + x;
|
||||
return (uint64_t)(InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + (int64_t)x);
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - x;
|
||||
return (uint64_t)(InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - (int64_t)x);
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new)
|
||||
{
|
||||
return InterlockedCompareExchange64((int64_t *)v, _new, old);
|
||||
return (uint64_t)(InterlockedCompareExchange64((int64_t *)v, _new, old));
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
|
||||
return (uint64_t)InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x));
|
||||
return (uint64_t)InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x));
|
||||
}
|
||||
|
||||
/* Signed */
|
||||
@@ -103,32 +103,32 @@ ATOMIC_INLINE int64_t atomic_fetch_and_sub_int64(int64_t *p, int64_t x)
|
||||
/* Unsigned */
|
||||
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
return InterlockedExchangeAdd(p, x) + x;
|
||||
return (uint32_t)InterlockedExchangeAdd(p, x) + x;
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
return InterlockedExchangeAdd(p, -((int32_t)x)) - x;
|
||||
return (uint32_t)InterlockedExchangeAdd(p, -((int32_t)x)) - x;
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new)
|
||||
{
|
||||
return InterlockedCompareExchange((long *)v, _new, old);
|
||||
return (uint32_t)InterlockedCompareExchange((long *)v, _new, old);
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
return InterlockedExchangeAdd(p, x);
|
||||
return (uint32_t)InterlockedExchangeAdd(p, x);
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
return InterlockedOr((long *)p, x);
|
||||
return (uint32_t)InterlockedOr((long *)p, x);
|
||||
}
|
||||
|
||||
ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
return InterlockedAnd((long *)p, x);
|
||||
return (uint32_t)InterlockedAnd((long *)p, x);
|
||||
}
|
||||
|
||||
/* Signed */
|
||||
@@ -205,9 +205,9 @@ ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b)
|
||||
ATOMIC_INLINE int8_t atomic_fetch_and_and_int8(int8_t *p, int8_t b)
|
||||
{
|
||||
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
|
||||
return InterlockedAnd8((char *)p, (char)b);
|
||||
return (int8_t)InterlockedAnd8((char *)p, (char)b);
|
||||
#else
|
||||
return _InterlockedAnd8((char *)p, (char)b);
|
||||
return (int8_t)_InterlockedAnd8((char *)p, (char)b);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -215,9 +215,9 @@ ATOMIC_INLINE int8_t atomic_fetch_and_and_int8(int8_t *p, int8_t b)
|
||||
ATOMIC_INLINE int8_t atomic_fetch_and_or_int8(int8_t *p, int8_t b)
|
||||
{
|
||||
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
|
||||
return InterlockedOr8((char *)p, (char)b);
|
||||
return (int8_t)InterlockedOr8((char *)p, (char)b);
|
||||
#else
|
||||
return _InterlockedOr8((char *)p, (char)b);
|
||||
return (int8_t)_InterlockedOr8((char *)p, (char)b);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -21,6 +21,7 @@
|
||||
set(INC
|
||||
.
|
||||
../atomic
|
||||
../../source/blender/blenlib
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
@@ -409,7 +409,7 @@ static void print_memhead_backtrace(MemHead *memh)
|
||||
(void)memh; /* Ignored. */
|
||||
}
|
||||
# endif /* defined(__linux__) || defined(__APPLE__) */
|
||||
#endif /* DEBUG_BACKTRACE */
|
||||
#endif /* DEBUG_BACKTRACE */
|
||||
|
||||
static void make_memhead_header(MemHead *memh, size_t len, const char *str)
|
||||
{
|
||||
|
@@ -30,6 +30,7 @@
|
||||
|
||||
/* to ensure strict conversions */
|
||||
#include "../../source/blender/blenlib/BLI_strict_flags.h"
|
||||
#include "../../source/blender/blenlib/BLI_asan.h"
|
||||
|
||||
#include "atomic_ops.h"
|
||||
#include "mallocn_intern.h"
|
||||
@@ -59,6 +60,9 @@ enum {
|
||||
#define MEMHEAD_ALIGNED_FROM_PTR(ptr) (((MemHeadAligned *)ptr) - 1)
|
||||
#define MEMHEAD_IS_ALIGNED(memhead) ((memhead)->len & (size_t)MEMHEAD_ALIGN_FLAG)
|
||||
|
||||
#define MEM_POISON_MEMHEAD(vmemh) BLI_asan_poison(MEMHEAD_FROM_PTR(vmemh), sizeof(MemHead))
|
||||
#define MEM_UNPOISON_MEMHEAD(vmemh) BLI_asan_unpoison(MEMHEAD_FROM_PTR(vmemh), sizeof(MemHead))
|
||||
|
||||
/* Uncomment this to have proper peak counter. */
|
||||
#define USE_ATOMIC_MAX
|
||||
|
||||
@@ -93,7 +97,13 @@ print_error(const char *str, ...)
|
||||
size_t MEM_lockfree_allocN_len(const void *vmemh)
|
||||
{
|
||||
if (vmemh) {
|
||||
return MEMHEAD_FROM_PTR(vmemh)->len & ~((size_t)(MEMHEAD_ALIGN_FLAG));
|
||||
size_t ret;
|
||||
|
||||
MEM_UNPOISON_MEMHEAD(vmemh);
|
||||
ret = MEMHEAD_FROM_PTR(vmemh)->len & ~((size_t)(MEMHEAD_ALIGN_FLAG));
|
||||
MEM_POISON_MEMHEAD(vmemh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -119,6 +129,8 @@ void MEM_lockfree_freeN(void *vmemh)
|
||||
atomic_sub_and_fetch_u(&totblock, 1);
|
||||
atomic_sub_and_fetch_z(&mem_in_use, len);
|
||||
|
||||
MEM_UNPOISON_MEMHEAD(vmemh);
|
||||
|
||||
if (UNLIKELY(malloc_debug_memset && len)) {
|
||||
memset(memh + 1, 255, len);
|
||||
}
|
||||
@@ -137,6 +149,9 @@ void *MEM_lockfree_dupallocN(const void *vmemh)
|
||||
if (vmemh) {
|
||||
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
|
||||
const size_t prev_size = MEM_lockfree_allocN_len(vmemh);
|
||||
|
||||
MEM_UNPOISON_MEMHEAD(vmemh);
|
||||
|
||||
if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) {
|
||||
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
|
||||
newp = MEM_lockfree_mallocN_aligned(
|
||||
@@ -145,6 +160,8 @@ void *MEM_lockfree_dupallocN(const void *vmemh)
|
||||
else {
|
||||
newp = MEM_lockfree_mallocN(prev_size, "dupli_malloc");
|
||||
}
|
||||
|
||||
MEM_POISON_MEMHEAD(vmemh);
|
||||
memcpy(newp, vmemh, prev_size);
|
||||
}
|
||||
return newp;
|
||||
@@ -158,6 +175,8 @@ void *MEM_lockfree_reallocN_id(void *vmemh, size_t len, const char *str)
|
||||
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
|
||||
size_t old_len = MEM_lockfree_allocN_len(vmemh);
|
||||
|
||||
MEM_UNPOISON_MEMHEAD(vmemh);
|
||||
|
||||
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
|
||||
newp = MEM_lockfree_mallocN(len, "realloc");
|
||||
}
|
||||
@@ -166,6 +185,8 @@ void *MEM_lockfree_reallocN_id(void *vmemh, size_t len, const char *str)
|
||||
newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "realloc");
|
||||
}
|
||||
|
||||
MEM_POISON_MEMHEAD(vmemh);
|
||||
|
||||
if (newp) {
|
||||
if (len < old_len) {
|
||||
/* shrink */
|
||||
@@ -194,6 +215,8 @@ void *MEM_lockfree_recallocN_id(void *vmemh, size_t len, const char *str)
|
||||
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
|
||||
size_t old_len = MEM_lockfree_allocN_len(vmemh);
|
||||
|
||||
MEM_UNPOISON_MEMHEAD(vmemh);
|
||||
|
||||
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
|
||||
newp = MEM_lockfree_mallocN(len, "recalloc");
|
||||
}
|
||||
@@ -201,6 +224,7 @@ void *MEM_lockfree_recallocN_id(void *vmemh, size_t len, const char *str)
|
||||
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
|
||||
newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "recalloc");
|
||||
}
|
||||
MEM_POISON_MEMHEAD(vmemh);
|
||||
|
||||
if (newp) {
|
||||
if (len < old_len) {
|
||||
@@ -241,6 +265,7 @@ void *MEM_lockfree_callocN(size_t len, const char *str)
|
||||
atomic_add_and_fetch_z(&mem_in_use, len);
|
||||
update_maximum(&peak_mem, mem_in_use);
|
||||
|
||||
MEM_POISON_MEMHEAD(PTR_FROM_MEMHEAD(memh));
|
||||
return PTR_FROM_MEMHEAD(memh);
|
||||
}
|
||||
print_error("Calloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
|
||||
@@ -286,6 +311,8 @@ void *MEM_lockfree_mallocN(size_t len, const char *str)
|
||||
atomic_add_and_fetch_z(&mem_in_use, len);
|
||||
update_maximum(&peak_mem, mem_in_use);
|
||||
|
||||
MEM_POISON_MEMHEAD(PTR_FROM_MEMHEAD(memh));
|
||||
|
||||
return PTR_FROM_MEMHEAD(memh);
|
||||
}
|
||||
print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
|
||||
@@ -357,6 +384,8 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str
|
||||
atomic_add_and_fetch_z(&mem_in_use, len);
|
||||
update_maximum(&peak_mem, mem_in_use);
|
||||
|
||||
MEM_POISON_MEMHEAD(PTR_FROM_MEMHEAD(memh));
|
||||
|
||||
return PTR_FROM_MEMHEAD(memh);
|
||||
}
|
||||
print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
|
||||
|
@@ -70,9 +70,9 @@ static int check_if_canceled(float progress,
|
||||
return cancel;
|
||||
}
|
||||
|
||||
void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
void (*update_cb)(void *, float progress, int *cancel),
|
||||
void *update_cb_data)
|
||||
ATTR_NO_OPT void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
void (*update_cb)(void *, float progress, int *cancel),
|
||||
void *update_cb_data)
|
||||
{
|
||||
Parametrizer field;
|
||||
VertexMap vertexMap;
|
||||
@@ -80,6 +80,12 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
/* Get remeshing parameters. */
|
||||
int faces = qrd->target_faces;
|
||||
|
||||
field.flag_adaptive_scale = 1;
|
||||
field.flag_minimum_cost_flow = 1;
|
||||
field.flag_preserve_boundary = 1;
|
||||
field.flag_preserve_sharp = 1;
|
||||
// field.flag_aggresive_sat = 1;
|
||||
|
||||
if (qrd->preserve_sharp) {
|
||||
field.flag_preserve_sharp = 1;
|
||||
}
|
||||
@@ -106,6 +112,7 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
/* Copy mesh to quadriflow data structures. */
|
||||
std::vector<Vector3d> positions;
|
||||
std::vector<uint32_t> indices;
|
||||
std::vector<uint32_t> eflags;
|
||||
std::vector<ObjVertex> vertices;
|
||||
|
||||
for (int i = 0; i < qrd->totverts; i++) {
|
||||
@@ -114,16 +121,18 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
}
|
||||
|
||||
for (int q = 0; q < qrd->totfaces; q++) {
|
||||
Vector3i f(qrd->faces[q * 3], qrd->faces[q * 3 + 1], qrd->faces[q * 3 + 2]);
|
||||
Vector3i f(qrd->faces[q].v[0], qrd->faces[q].v[1], qrd->faces[q].v[2]);
|
||||
|
||||
ObjVertex tri[6];
|
||||
int nVertices = 3;
|
||||
const int nVertices = 3;
|
||||
|
||||
tri[0] = ObjVertex(f[0]);
|
||||
tri[1] = ObjVertex(f[1]);
|
||||
tri[2] = ObjVertex(f[2]);
|
||||
|
||||
for (int i = 0; i < nVertices; ++i) {
|
||||
eflags.push_back(qrd->faces[q].eflag[i]);
|
||||
|
||||
const ObjVertex &v = tri[i];
|
||||
VertexMap::const_iterator it = vertexMap.find(v);
|
||||
if (it == vertexMap.end()) {
|
||||
@@ -138,7 +147,10 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
}
|
||||
|
||||
field.F.resize(3, indices.size() / 3);
|
||||
// field.FF.resize(3, indices.size() / 3);
|
||||
|
||||
memcpy(field.F.data(), indices.data(), sizeof(uint32_t) * indices.size());
|
||||
// memcpy(field.FF.data(), eflags.data(), sizeof(uint32_t) * eflags.size());
|
||||
|
||||
field.V.resize(3, vertices.size());
|
||||
for (uint32_t i = 0; i < vertices.size(); ++i) {
|
||||
@@ -157,12 +169,17 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
return;
|
||||
}
|
||||
|
||||
const int steps = 2;
|
||||
|
||||
/* Setup mesh boundary constraints if needed */
|
||||
if (field.flag_preserve_boundary) {
|
||||
#if 0
|
||||
if (true) { // field.flag_preserve_boundary) {
|
||||
Hierarchy &mRes = field.hierarchy;
|
||||
mRes.clearConstraints();
|
||||
|
||||
for (uint32_t i = 0; i < 3 * mRes.mF.cols(); ++i) {
|
||||
if (mRes.mE2E[i] == -1) {
|
||||
if (mRes.mFF((i) % 3, i / 3) & QFLOW_CONSTRAINED) {
|
||||
// if (mRes.mE2E[i] == -1) {
|
||||
uint32_t i0 = mRes.mF(i % 3, i / 3);
|
||||
uint32_t i1 = mRes.mF((i + 1) % 3, i / 3);
|
||||
Vector3d p0 = mRes.mV[0].col(i0), p1 = mRes.mV[0].col(i1);
|
||||
@@ -172,15 +189,20 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
mRes.mCO[0].col(i0) = p0;
|
||||
mRes.mCO[0].col(i1) = p1;
|
||||
mRes.mCQ[0].col(i0) = mRes.mCQ[0].col(i1) = edge;
|
||||
mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] = 1.0;
|
||||
mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] = 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
mRes.propagateConstraints();
|
||||
for (int j = 0; j < 10; j++) {
|
||||
mRes.propagateConstraints();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Optimize the mesh field orientations (tangental field etc) */
|
||||
Optimizer::optimize_orientations(field.hierarchy);
|
||||
for (int i = 0; i < steps; i++) {
|
||||
Optimizer::optimize_orientations(field.hierarchy);
|
||||
}
|
||||
field.ComputeOrientationSingularities();
|
||||
|
||||
if (check_if_canceled(0.3f, update_cb, update_cb_data)) {
|
||||
@@ -195,11 +217,13 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
|
||||
return;
|
||||
}
|
||||
|
||||
Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale);
|
||||
field.flag_adaptive_scale = 1;
|
||||
|
||||
Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale);
|
||||
for (int i = 0; i < steps; i++) {
|
||||
Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale);
|
||||
}
|
||||
|
||||
for (int i = 0; i < steps; i++) {
|
||||
Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale);
|
||||
}
|
||||
field.ComputePositionSingularities();
|
||||
|
||||
if (check_if_canceled(0.5f, update_cb, update_cb_data)) {
|
||||
|
@@ -23,9 +23,16 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum { QFLOW_CONSTRAINED = 1 };
|
||||
|
||||
typedef struct QuadriflowFace {
|
||||
int v[3];
|
||||
char eflag[3];
|
||||
} QuadriflowFace;
|
||||
|
||||
typedef struct QuadriflowRemeshData {
|
||||
float *verts;
|
||||
int *faces;
|
||||
QuadriflowFace *faces;
|
||||
int totfaces;
|
||||
int totverts;
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
release/datafiles/icons/brush.sculpt.paint.dat
Normal file
BIN
release/datafiles/icons/brush.sculpt.paint.dat
Normal file
Binary file not shown.
BIN
release/datafiles/icons/brush.sculpt.smear.dat
Normal file
BIN
release/datafiles/icons/brush.sculpt.smear.dat
Normal file
Binary file not shown.
BIN
release/datafiles/icons/brush.sculpt.vcol_boundary.dat
Normal file
BIN
release/datafiles/icons/brush.sculpt.vcol_boundary.dat
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Submodule release/datafiles/locale updated: 62e82958a7...326997b913
Submodule release/scripts/addons updated: 4475cbd11a...59c8409947
Submodule release/scripts/addons_contrib updated: 788441f293...98f6085e9d
@@ -549,15 +549,27 @@ def brush_settings(layout, context, brush, popover=False):
|
||||
if context.preferences.experimental.use_sculpt_tools_tilt and capabilities.has_tilt:
|
||||
layout.prop(brush, "tilt_strength_factor", slider=True)
|
||||
|
||||
UnifiedPaintPanel.prop_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"hard_edge_mode",
|
||||
slider=True,
|
||||
unified_name="use_unified_hard_edge_mode",
|
||||
)
|
||||
|
||||
row = layout.row(align=True)
|
||||
|
||||
row.prop(brush, "hardness", slider=True)
|
||||
row.prop(brush, "invert_hardness_pressure", text="")
|
||||
row.prop(brush, "use_hardness_pressure", text="")
|
||||
|
||||
# auto_smooth_factor and use_inverse_smooth_pressure
|
||||
if capabilities.has_auto_smooth:
|
||||
box = layout.box().column() #.column() is a bit more compact
|
||||
|
||||
UnifiedPaintPanel.prop_unified(
|
||||
layout,
|
||||
box,
|
||||
context,
|
||||
brush,
|
||||
"auto_smooth_factor",
|
||||
@@ -565,13 +577,70 @@ def brush_settings(layout, context, brush, popover=False):
|
||||
slider=True,
|
||||
)
|
||||
|
||||
# topology_rake_factor
|
||||
box.prop(brush, "boundary_smooth_factor")
|
||||
box.prop(brush, "use_weighted_smooth")
|
||||
box.prop(brush, "preserve_faceset_boundary")
|
||||
|
||||
if brush.preserve_faceset_boundary:
|
||||
box.prop(brush, "autosmooth_fset_slide")
|
||||
|
||||
box.prop(brush, "use_custom_auto_smooth_spacing", text="Custom Spacing")
|
||||
if brush.use_custom_auto_smooth_spacing:
|
||||
UnifiedPaintPanel.prop_unified(
|
||||
box,
|
||||
context,
|
||||
brush,
|
||||
"auto_smooth_spacing",
|
||||
slider=True,
|
||||
text="Spacing"
|
||||
)
|
||||
UnifiedPaintPanel.prop_unified(
|
||||
box,
|
||||
context,
|
||||
brush,
|
||||
"auto_smooth_projection",
|
||||
slider=True
|
||||
)
|
||||
UnifiedPaintPanel.prop_unified(
|
||||
box,
|
||||
context,
|
||||
brush,
|
||||
"auto_smooth_radius_factor",
|
||||
slider=True
|
||||
)
|
||||
elif brush.sculpt_tool == "SMOOTH":
|
||||
UnifiedPaintPanel.prop_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"auto_smooth_projection",
|
||||
slider=True
|
||||
)
|
||||
|
||||
|
||||
if capabilities.has_vcol_boundary_smooth:
|
||||
layout.prop(brush, "vcol_boundary_factor", slider=True)
|
||||
|
||||
if (
|
||||
capabilities.has_topology_rake and
|
||||
context.sculpt_object.use_dynamic_topology_sculpting
|
||||
):
|
||||
layout.prop(brush, "topology_rake_factor", slider=True)
|
||||
box = layout.box().column() #.column() is a bit more compact
|
||||
|
||||
box.prop(brush, "topology_rake_factor", slider=True)
|
||||
box.prop(brush, "use_custom_topology_rake_spacing", text="Custom Spacing")
|
||||
|
||||
if brush.use_custom_topology_rake_spacing:
|
||||
box.prop(brush, "topology_rake_spacing", text="Spacing")
|
||||
box.prop(brush, "topology_rake_projection")
|
||||
|
||||
box.prop(brush, "topology_rake_radius_factor", slider=True)
|
||||
box.prop(brush, "use_curvature_rake")
|
||||
box.prop(brush, "ignore_falloff_for_topology_rake")
|
||||
|
||||
if context.sculpt_object.use_dynamic_topology_sculpting:
|
||||
layout.prop(brush.dyntopo, "disabled", text="Disable Dyntopo")
|
||||
|
||||
# normal_weight
|
||||
if capabilities.has_normal_weight:
|
||||
layout.prop(brush, "normal_weight", slider=True)
|
||||
@@ -630,6 +699,10 @@ def brush_settings(layout, context, brush, popover=False):
|
||||
|
||||
# Per sculpt tool options.
|
||||
|
||||
if sculpt_tool == "VCOL_BOUNDARY":
|
||||
row = layout.row()
|
||||
row.prop(brush, "vcol_boundary_exponent")
|
||||
|
||||
if sculpt_tool == 'CLAY_STRIPS':
|
||||
row = layout.row()
|
||||
row.prop(brush, "tip_roundness")
|
||||
@@ -756,7 +829,15 @@ def brush_settings(layout, context, brush, popover=False):
|
||||
|
||||
elif sculpt_tool == 'SMOOTH':
|
||||
col = layout.column()
|
||||
col.prop(brush, "boundary_smooth_factor")
|
||||
|
||||
col.prop(brush, "use_weighted_smooth")
|
||||
col.prop(brush, "preserve_faceset_boundary")
|
||||
if brush.preserve_faceset_boundary:
|
||||
col.prop(brush, "autosmooth_fset_slide")
|
||||
|
||||
col.prop(brush, "smooth_deform_type")
|
||||
|
||||
if brush.smooth_deform_type == 'SURFACE':
|
||||
col.prop(brush, "surface_smooth_shape_preservation")
|
||||
col.prop(brush, "surface_smooth_current_vertex")
|
||||
@@ -916,6 +997,14 @@ def brush_settings_advanced(layout, context, brush, popover=False):
|
||||
# topology automasking
|
||||
col.prop(brush, "use_automasking_topology", text="Topology")
|
||||
|
||||
col.prop(brush, "use_automasking_concave")
|
||||
|
||||
col2 = col.column()
|
||||
col2.enabled = brush.use_automasking_concave
|
||||
|
||||
col2.prop(brush, "concave_mask_factor", text="Cavity Factor")
|
||||
col2.prop(brush, "invert_automasking_concavity", text="Invert Cavity Mask")
|
||||
|
||||
# face masks automasking
|
||||
col.prop(brush, "use_automasking_face_sets", text="Face Sets")
|
||||
|
||||
|
@@ -1294,7 +1294,9 @@ class _defs_sculpt:
|
||||
# Use 'bpy.context' instead of 'context' since it can be None.
|
||||
prefs = bpy.context.preferences
|
||||
if not prefs.experimental.use_sculpt_vertex_colors:
|
||||
exclude_filter = {'PAINT', 'SMEAR'}
|
||||
exclude_filter = {'PAINT' : True, 'SMEAR' : True}
|
||||
if not prefs.experimental.use_sculpt_uvsmooth:
|
||||
exclude_filter['UV_SMOOTH'] = True
|
||||
|
||||
return generate_from_enum_ex(
|
||||
context,
|
||||
|
@@ -2248,6 +2248,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
|
||||
self._draw_items(
|
||||
context, (
|
||||
({"property": "use_sculpt_vertex_colors"}, "T71947"),
|
||||
({"property": "use_sculpt_uvsmooth"}, ""),
|
||||
({"property": "use_sculpt_tools_tilt"}, "T82877"),
|
||||
({"property": "use_extended_asset_browser"}, ("project/view/130/", "Project Page")),
|
||||
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
|
||||
|
@@ -171,6 +171,7 @@ class VIEW3D_HT_tool_header(Header):
|
||||
row.popover(panel="VIEW3D_PT_tools_weightpaint_symmetry_for_topbar", text="")
|
||||
elif mode_string == 'SCULPT':
|
||||
row.popover(panel="VIEW3D_PT_sculpt_symmetry_for_topbar", text="")
|
||||
layout.prop(context.object.data, "use_fset_boundary_mirror");
|
||||
elif mode_string == 'PAINT_VERTEX':
|
||||
row.popover(panel="VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar", text="")
|
||||
|
||||
|
@@ -17,7 +17,7 @@
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
from bpy.types import Menu, Panel, UIList
|
||||
from bpy.types import Menu, Panel, UIList, WindowManager
|
||||
from bl_ui.properties_grease_pencil_common import (
|
||||
GreasePencilSculptOptionsPanel,
|
||||
GreasePencilDisplayPanel,
|
||||
@@ -754,10 +754,78 @@ class VIEW3D_PT_tools_brush_falloff_normal(View3DPaintPanel, Panel):
|
||||
layout.prop(ipaint, "normal_angle", text="Angle")
|
||||
|
||||
|
||||
# TODO, move to space_view3d.py
|
||||
class VIEW3D_PT_sculpt_dyntopo_advanced(Panel, View3DPaintPanel):
|
||||
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
|
||||
bl_label = "Dyntopo (Advanced)"
|
||||
#bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_ui_units_x = 12
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
paint_settings = cls.paint_settings(context)
|
||||
return (context.sculpt_object and context.tool_settings.sculpt and paint_settings)
|
||||
|
||||
def draw_header(self, context):
|
||||
pass
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
tool_settings = context.tool_settings
|
||||
sculpt = tool_settings.sculpt
|
||||
settings = self.paint_settings(context)
|
||||
brush = settings.brush
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="Local Brush Settings")
|
||||
|
||||
row = col.row()
|
||||
row.prop(brush.dyntopo, "disabled", text="Disable Dyntopo locally for this brush")
|
||||
|
||||
col.label(text="Overrides")
|
||||
inherit_all = "ALL" in brush.dyntopo.inherit
|
||||
|
||||
col.prop_enum(brush.dyntopo, "inherit", value="ALL", text="Use All Defaults", icon="LOCKED" if inherit_all else "UNLOCKED")
|
||||
|
||||
def do_prop(key):
|
||||
row = col.row()
|
||||
if key.upper() in brush.dyntopo.inherit:
|
||||
icon = "UNLOCKED"
|
||||
else:
|
||||
icon = "LOCKED"
|
||||
|
||||
row.prop_enum(brush.dyntopo, "inherit", value=key.upper(), icon=icon, text="")
|
||||
|
||||
row2 = row.row()
|
||||
row2.prop(brush.dyntopo, key)
|
||||
|
||||
if icon == "UNLOCKED":
|
||||
row2.enabled = False
|
||||
|
||||
if inherit_all:
|
||||
row.enabled = False
|
||||
|
||||
col = layout.column()
|
||||
do_prop("subdivide")
|
||||
do_prop("collapse")
|
||||
do_prop("cleanup")
|
||||
do_prop("spacing")
|
||||
do_prop("local_subdivide")
|
||||
do_prop("local_collapse")
|
||||
do_prop("detail_size")
|
||||
do_prop("detail_range")
|
||||
do_prop("detail_percent")
|
||||
do_prop("constant_detail")
|
||||
do_prop("mode")
|
||||
do_prop("radius_scale")
|
||||
|
||||
# TODO, move to space_view3d.py
|
||||
class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
|
||||
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
|
||||
bl_label = "Dyntopo"
|
||||
bl_label = "Dynamic Mode"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_ui_units_x = 12
|
||||
|
||||
@@ -789,6 +857,8 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
|
||||
col = layout.column()
|
||||
col.active = context.sculpt_object.use_dynamic_topology_sculpting
|
||||
|
||||
col.prop(sculpt, "use_dyntopo");
|
||||
|
||||
sub = col.column()
|
||||
sub.active = (brush and brush.sculpt_tool != 'MASK')
|
||||
if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
|
||||
@@ -806,7 +876,12 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
|
||||
if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
|
||||
col.operator("sculpt.detail_flood_fill")
|
||||
|
||||
col.prop(sculpt, "use_dyntopo_cleanup")
|
||||
col.prop(sculpt, "use_smooth_shading")
|
||||
col.prop(sculpt, "use_flat_vcol_shading")
|
||||
|
||||
col.prop(sculpt, "dyntopo_spacing")
|
||||
col.prop(sculpt, "dyntopo_radius_scale");
|
||||
|
||||
|
||||
class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
|
||||
@@ -865,6 +940,7 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
|
||||
col = layout.column(heading="Display", align=True)
|
||||
col.prop(sculpt, "show_low_resolution")
|
||||
col.prop(sculpt, "use_sculpt_delay_updates")
|
||||
col.prop(sculpt, "use_fast_draw")
|
||||
col.prop(sculpt, "use_deform_only")
|
||||
|
||||
col.separator()
|
||||
@@ -938,6 +1014,7 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
|
||||
row.prop(sculpt, "tile_z", text="Z", toggle=True)
|
||||
|
||||
layout.prop(sculpt, "use_symmetry_feather", text="Feather")
|
||||
layout.prop(mesh, "use_fset_boundary_mirror")
|
||||
layout.prop(sculpt, "radial_symmetry", text="Radial")
|
||||
layout.prop(sculpt, "tile_offset", text="Tile Offset")
|
||||
|
||||
@@ -945,6 +1022,7 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
|
||||
|
||||
layout.prop(sculpt, "symmetrize_direction")
|
||||
layout.operator("sculpt.symmetrize")
|
||||
layout.prop(WindowManager.operator_properties_last("sculpt.symmetrize"), "merge_tolerance")
|
||||
|
||||
|
||||
class VIEW3D_PT_sculpt_symmetry_for_topbar(Panel):
|
||||
@@ -2278,6 +2356,7 @@ classes = (
|
||||
VIEW3D_PT_tools_grease_pencil_brush_vertex_color,
|
||||
VIEW3D_PT_tools_grease_pencil_brush_vertex_palette,
|
||||
VIEW3D_PT_tools_grease_pencil_brush_vertex_falloff,
|
||||
VIEW3D_PT_sculpt_dyntopo_advanced
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
@@ -39,7 +39,7 @@ extern "C" {
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 22
|
||||
#define BLENDER_FILE_SUBVERSION 23
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
@@ -36,6 +36,8 @@ struct Main;
|
||||
struct Scene;
|
||||
struct ToolSettings;
|
||||
struct UnifiedPaintSettings;
|
||||
struct DynTopoSettings;
|
||||
struct Sculpt;
|
||||
|
||||
// enum eCurveMappingPreset;
|
||||
|
||||
@@ -151,6 +153,13 @@ void BKE_brush_scale_size(int *r_brush_size,
|
||||
/* debugging only */
|
||||
void BKE_brush_debug_print_state(struct Brush *br);
|
||||
|
||||
void BKE_brush_get_dyntopo(struct Brush *brush, struct Sculpt *sd, struct DynTopoSettings *out);
|
||||
|
||||
bool BKE_brush_hard_edge_mode_get(const struct Scene *scene, const struct Brush *brush);
|
||||
void BKE_brush_hard_edge_mode_set(struct Scene *scene, struct Brush *brush, bool val);
|
||||
|
||||
float BKE_brush_fset_slide_get(const struct Scene *scene, const struct Brush *brush);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
129
source/blender/blenkernel/BKE_brush_engine.h
Normal file
129
source/blender/blenkernel/BKE_brush_engine.h
Normal file
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
* \brief New brush engine for sculpt
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "RNA_types.h"
|
||||
|
||||
/*
|
||||
The new brush engine is based on command lists. These lists
|
||||
will eventually be created by a node editor.
|
||||
|
||||
Key is the concept of BrushChannels. A brush channel is
|
||||
a logical parameter with a type, input settings (e.g. pen),
|
||||
a falloff curve, etc.
|
||||
|
||||
Brush channels have a concept of inheritance. There is a
|
||||
BrushChannelSet (collection of channels) in Sculpt,
|
||||
in Brush, and in BrushCommand. Inheritence behavior
|
||||
is controller via BrushChannel->flag.
|
||||
|
||||
This should completely replace UnifiedPaintSettings.
|
||||
*/
|
||||
struct BrushChannel;
|
||||
|
||||
#include "BLO_read_write.h"
|
||||
#include "DNA_sculpt_brush_types.h"
|
||||
|
||||
typedef struct BrushMappingDef {
|
||||
int curve;
|
||||
bool enabled;
|
||||
bool inv;
|
||||
float min, max;
|
||||
int blendmode;
|
||||
} BrushMappingDef;
|
||||
|
||||
typedef struct BrushMappingPreset {
|
||||
// must match order of BRUSH_MAPPING_XXX enums
|
||||
struct BrushMappingDef pressure, xtilt, ytilt, angle, speed;
|
||||
} BrushMappingPreset;
|
||||
|
||||
#define MAX_BRUSH_ENUM_DEF 32
|
||||
|
||||
typedef struct BrushEnumDef {
|
||||
EnumPropertyItem items[MAX_BRUSH_ENUM_DEF];
|
||||
} BrushEnumDef;
|
||||
|
||||
typedef struct BrushChannelType {
|
||||
char name[32], idname[32];
|
||||
float min, max, soft_min, soft_max;
|
||||
BrushMappingPreset mappings;
|
||||
|
||||
int type, flag;
|
||||
int ivalue;
|
||||
float fvalue;
|
||||
BrushEnumDef enumdef; // if an enum type
|
||||
} BrushChannelType;
|
||||
|
||||
typedef struct BrushCommand {
|
||||
int tool;
|
||||
struct BrushChannelSet *params;
|
||||
struct BrushChannelSet *params_final;
|
||||
int totparam;
|
||||
} BrushCommand;
|
||||
|
||||
typedef struct BrushCommandList {
|
||||
BrushCommand *commands;
|
||||
int totcommand;
|
||||
} BrushCommandList;
|
||||
|
||||
void BKE_brush_channel_free(BrushChannel *ch);
|
||||
void BKE_brush_channel_copy(BrushChannel *dst, BrushChannel *src);
|
||||
void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def);
|
||||
BrushChannelSet *BKE_brush_channelset_create();
|
||||
|
||||
void BKE_brush_channelset_free(BrushChannelSet *chset);
|
||||
void BKE_brush_channelset_add(BrushChannelSet *chset, BrushChannel *ch);
|
||||
|
||||
BrushChannel *BKE_brush_channelset_lookup(BrushChannelSet *chset, const char *idname);
|
||||
|
||||
bool BKE_brush_channelset_has(BrushChannelSet *chset, const char *idname);
|
||||
|
||||
void BKE_brush_channelset_add_builtin(BrushChannelSet *chset, const char *idname);
|
||||
bool BKE_brush_channelset_ensure_builtin(BrushChannelSet *chset, const char *idname);
|
||||
|
||||
void BKE_brush_channelset_merge(BrushChannelSet *dst,
|
||||
BrushChannelSet *child,
|
||||
BrushChannelSet *parent);
|
||||
|
||||
void BKE_brush_resolve_channels(struct Brush *brush, struct Sculpt *sd);
|
||||
int BKE_brush_channel_get_int(BrushChannelSet *chset, char *idname);
|
||||
float BKE_brush_channel_get_float(BrushChannelSet *chset, char *idname);
|
||||
float BKE_brush_channel_set_float(BrushChannelSet *chset, char *idname, float val);
|
||||
void BKE_brush_init_toolsettings(struct Sculpt *sd);
|
||||
void BKE_brush_builtin_create(struct Brush *brush, int tool);
|
||||
BrushCommandList *BKE_brush_commandlist_create();
|
||||
void BKE_brush_commandlist_free(BrushCommandList *cl);
|
||||
BrushCommand *BKE_brush_commandlist_add(BrushCommandList *cl);
|
||||
BrushCommand *BKE_brush_command_init(BrushCommand *command, int tool);
|
||||
void BKE_builtin_commandlist_create(BrushChannelSet *chset, BrushCommandList *cl, int tool);
|
||||
void BKE_brush_channelset_read(BlendDataReader *reader, BrushChannelSet *cset);
|
||||
void BKE_brush_channelset_write(BlendWriter *writer, BrushChannelSet *cset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -105,6 +105,8 @@ bool CustomData_has_math(const struct CustomData *data);
|
||||
bool CustomData_has_interp(const struct CustomData *data);
|
||||
bool CustomData_bmesh_has_free(const struct CustomData *data);
|
||||
|
||||
bool CustomData_layout_is_same(const struct CustomData *_a, const struct CustomData *_b);
|
||||
|
||||
/**
|
||||
* Checks if any of the customdata layers is referenced.
|
||||
*/
|
||||
@@ -141,6 +143,10 @@ void CustomData_copy(const struct CustomData *source,
|
||||
/* BMESH_TODO, not really a public function but readfile.c needs it */
|
||||
void CustomData_update_typemap(struct CustomData *data);
|
||||
|
||||
/* copies all customdata layers without allocating data,
|
||||
* and without respect to type masks or NO_COPY/etc flags*/
|
||||
void CustomData_copy_all_layout(const struct CustomData *source, struct CustomData *dest);
|
||||
|
||||
/* same as the above, except that this will preserve existing layers, and only
|
||||
* add the layers that were not there yet */
|
||||
bool CustomData_merge(const struct CustomData *source,
|
||||
@@ -277,6 +283,16 @@ void CustomData_copy_data_named(const struct CustomData *source,
|
||||
int dest_index,
|
||||
int count);
|
||||
void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count);
|
||||
|
||||
// ignores CD_MESH_ID layer if it exists
|
||||
void CustomData_bmesh_swap_data(struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
void *src_block,
|
||||
void **dest_block);
|
||||
|
||||
// simple pointer swap; will unswaps ids if a CD_MESH_ID layer exists
|
||||
void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2);
|
||||
|
||||
void CustomData_bmesh_copy_data(const struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
void *src_block,
|
||||
@@ -605,6 +621,11 @@ void CustomData_blend_write(struct BlendWriter *writer,
|
||||
struct ID *id);
|
||||
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
|
||||
|
||||
void CustomData_unmark_temporary_nocopy(struct CustomData *data);
|
||||
void CustomData_mark_temporary_nocopy(struct CustomData *data);
|
||||
|
||||
int CustomData_get_elem_size(CustomDataLayer *layer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -54,9 +54,11 @@ enum {
|
||||
DT_TYPE_UV = 1 << 24,
|
||||
DT_TYPE_SHARP_FACE = 1 << 25,
|
||||
DT_TYPE_FREESTYLE_FACE = 1 << 26,
|
||||
#define DT_TYPE_MAX 27
|
||||
DT_TYPE_PROPCOL = 1 << 27,
|
||||
#define DT_TYPE_MAX 28
|
||||
|
||||
DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT,
|
||||
DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT |
|
||||
DT_TYPE_PROPCOL,
|
||||
DT_TYPE_EDGE_ALL = DT_TYPE_SHARP_EDGE | DT_TYPE_SEAM | DT_TYPE_CREASE | DT_TYPE_BWEIGHT_EDGE |
|
||||
DT_TYPE_FREESTYLE_EDGE,
|
||||
DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_LNOR | DT_TYPE_UV,
|
||||
@@ -74,7 +76,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type);
|
||||
int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type);
|
||||
|
||||
#define DT_DATATYPE_IS_VERT(_dt) \
|
||||
ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT)
|
||||
ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT, DT_TYPE_PROPCOL)
|
||||
#define DT_DATATYPE_IS_EDGE(_dt) \
|
||||
ELEM(_dt, \
|
||||
DT_TYPE_CREASE, \
|
||||
@@ -94,7 +96,8 @@ enum {
|
||||
DT_MULTILAYER_INDEX_SHAPEKEY = 1,
|
||||
DT_MULTILAYER_INDEX_VCOL = 2,
|
||||
DT_MULTILAYER_INDEX_UV = 3,
|
||||
DT_MULTILAYER_INDEX_MAX = 4,
|
||||
DT_MULTILAYER_INDEX_PROPCOL = 4,
|
||||
DT_MULTILAYER_INDEX_MAX = 5,
|
||||
};
|
||||
|
||||
/* Below we keep positive values for real layers idx (generated dynamically). */
|
||||
|
24
source/blender/blenkernel/BKE_dyntopo.h
Normal file
24
source/blender/blenkernel/BKE_dyntopo.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
* \brief Dynamic topology remeshing API
|
||||
*/
|
||||
|
||||
typedef struct DynTopo DynTopo;
|
@@ -78,8 +78,12 @@ typedef struct FModifierTypeInfo {
|
||||
short size;
|
||||
/** #eFMI_Action_Types. */
|
||||
short acttype;
|
||||
#ifdef __cplusplus
|
||||
short requires_;
|
||||
#else
|
||||
/** #eFMI_Requirement_Flags. */
|
||||
short requires;
|
||||
#endif
|
||||
/** name of modifier in interface. */
|
||||
char name[64];
|
||||
/** name of struct for SDNA. */
|
||||
|
@@ -69,7 +69,8 @@ extern "C" {
|
||||
|
||||
/* *** mesh.c *** */
|
||||
|
||||
struct BMesh *BKE_mesh_to_bmesh_ex(const struct Mesh *me,
|
||||
struct BMesh *BKE_mesh_to_bmesh_ex(const struct Object *ob,
|
||||
const struct Mesh *me,
|
||||
const struct BMeshCreateParams *create_params,
|
||||
const struct BMeshFromMeshParams *convert_params);
|
||||
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
|
||||
@@ -636,7 +637,7 @@ void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
|
||||
|
||||
/* In DerivedMesh.cc */
|
||||
void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
|
||||
const CustomData_MeshMasks *cd_mask_finalize);
|
||||
const struct CustomData_MeshMasks *cd_mask_finalize);
|
||||
|
||||
/* **** Depsgraph evaluation **** */
|
||||
|
||||
|
@@ -105,20 +105,28 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly,
|
||||
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
|
||||
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
|
||||
|
||||
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const struct MPoly *mpoly,
|
||||
const struct MLoop *mloop,
|
||||
int totvert,
|
||||
int totpoly,
|
||||
int totloop);
|
||||
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const struct MPoly *mpoly,
|
||||
const struct MLoop *mloop,
|
||||
int totvert,
|
||||
int totpoly,
|
||||
int totloop);
|
||||
void BKE_mesh_vert_poly_map_create(
|
||||
MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const struct MVert *mvert, // only needed if sort_disk_cycles is true
|
||||
const struct MEdge *medge, // only needed if sort_disk_cycles is true
|
||||
const struct MPoly *mpoly,
|
||||
const struct MLoop *mloop,
|
||||
int totvert,
|
||||
int totpoly,
|
||||
int totloop,
|
||||
const bool sort_disk_cycles); // put polys in sorted geometric order
|
||||
void BKE_mesh_vert_loop_map_create(
|
||||
MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const struct MVert *mvert, // only needed if sort_disk_cycles is true
|
||||
const struct MEdge *medge, // only needed if sort_disk_cycles is true
|
||||
const struct MPoly *mpoly,
|
||||
const struct MLoop *mloop,
|
||||
int totvert,
|
||||
int totpoly,
|
||||
int totloop,
|
||||
const bool sort_disk_cycles); // put loops in sorted geometric order
|
||||
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const struct MVert *mvert,
|
||||
@@ -128,7 +136,13 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
|
||||
const struct MLoop *mloop,
|
||||
const int totloop);
|
||||
void BKE_mesh_vert_edge_map_create(
|
||||
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
|
||||
MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const struct MVert *mvert, // only needed if sort_disk_cycles is true
|
||||
const struct MEdge *medge,
|
||||
int totvert,
|
||||
int totedge,
|
||||
bool sort_disk_cycles); // sort verts in geometric order around edges
|
||||
void BKE_mesh_vert_edge_vert_map_create(
|
||||
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
|
||||
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
|
||||
|
@@ -32,7 +32,7 @@ struct Mesh;
|
||||
struct MirrorModifierData;
|
||||
struct Object;
|
||||
|
||||
struct Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct MirrorModifierData *mmd,
|
||||
struct Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct Object *ob, struct MirrorModifierData *mmd,
|
||||
const struct Mesh *mesh,
|
||||
int axis,
|
||||
const float plane_co[3],
|
||||
|
@@ -39,6 +39,7 @@ struct MultiresModifierData;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
struct SubdivCCG;
|
||||
struct BMesh;
|
||||
|
||||
struct MLoop;
|
||||
struct MLoopTri;
|
||||
@@ -217,6 +218,7 @@ BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3]
|
||||
const float dPdv[3],
|
||||
const int corner);
|
||||
|
||||
void BKE_multires_bmesh_space_set(struct Object *ob, struct BMesh *bm, int mode);
|
||||
/* Versioning. */
|
||||
|
||||
/* Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark
|
||||
|
@@ -25,6 +25,8 @@
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include "DNA_object_enums.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
#include "BKE_lib_id.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -154,8 +156,8 @@ bool BKE_object_obdata_is_libdata(const struct Object *ob);
|
||||
|
||||
struct Object *BKE_object_duplicate(struct Main *bmain,
|
||||
struct Object *ob,
|
||||
uint dupflag,
|
||||
const uint duplicate_options);
|
||||
eDupli_ID_Flags dupflag,
|
||||
const eLibIDDuplicateFlags duplicate_options);
|
||||
|
||||
void BKE_object_obdata_size_init(struct Object *ob, const float size);
|
||||
|
||||
|
@@ -23,15 +23,18 @@
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "BKE_pbvh.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "DNA_brush_enums.h"
|
||||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_object_enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct MDynTopoVert;
|
||||
struct BMFace;
|
||||
struct BMesh;
|
||||
struct BlendDataReader;
|
||||
@@ -342,6 +345,11 @@ typedef struct SculptClothSimulation {
|
||||
/** #PBVHNode pointer as a key, index in #SculptClothSimulation.node_state as value. */
|
||||
struct GHash *node_state_index;
|
||||
eSculptClothNodeSimState *node_state;
|
||||
|
||||
// persistent base customdata layer offsets
|
||||
int cd_pers_co;
|
||||
int cd_pers_no;
|
||||
int cd_pers_disp;
|
||||
} SculptClothSimulation;
|
||||
|
||||
typedef struct SculptPersistentBase {
|
||||
@@ -360,7 +368,8 @@ typedef struct SculptVertexInfo {
|
||||
|
||||
typedef struct SculptBoundaryEditInfo {
|
||||
/* Vertex index from where the topology propagation reached this vertex. */
|
||||
int original_vertex;
|
||||
SculptVertRef original_vertex;
|
||||
int original_vertex_i;
|
||||
|
||||
/* How many steps were needed to reach this vertex from the boundary. */
|
||||
int num_propagation_steps;
|
||||
@@ -371,13 +380,23 @@ typedef struct SculptBoundaryEditInfo {
|
||||
|
||||
/* Edge for drawing the boundary preview in the cursor. */
|
||||
typedef struct SculptBoundaryPreviewEdge {
|
||||
int v1;
|
||||
int v2;
|
||||
SculptVertRef v1;
|
||||
SculptVertRef v2;
|
||||
} SculptBoundaryPreviewEdge;
|
||||
|
||||
#define MAX_STORED_COTANGENTW_EDGES 7
|
||||
|
||||
typedef struct StoredCotangentW {
|
||||
float static_weights[MAX_STORED_COTANGENTW_EDGES];
|
||||
float *weights;
|
||||
int length;
|
||||
} StoredCotangentW;
|
||||
|
||||
typedef struct SculptBoundary {
|
||||
/* Vertex indices of the active boundary. */
|
||||
int *vertices;
|
||||
SculptVertRef *vertices;
|
||||
int *vertex_indices;
|
||||
|
||||
int vertices_capacity;
|
||||
int num_vertices;
|
||||
|
||||
@@ -386,6 +405,14 @@ typedef struct SculptBoundary {
|
||||
* a distance of 0. */
|
||||
float *distance;
|
||||
|
||||
float (*smoothco)[3];
|
||||
float *boundary_dist; // distances from verts to boundary
|
||||
float (*boundary_tangents)[3];
|
||||
|
||||
StoredCotangentW *boundary_cotangents;
|
||||
SculptVertRef *boundary_closest;
|
||||
int sculpt_totvert;
|
||||
|
||||
/* Data for drawing the preview. */
|
||||
SculptBoundaryPreviewEdge *edges;
|
||||
int edges_capacity;
|
||||
@@ -395,12 +422,12 @@ typedef struct SculptBoundary {
|
||||
bool forms_loop;
|
||||
|
||||
/* Initial vertex in the boundary which is closest to the current sculpt active vertex. */
|
||||
int initial_vertex;
|
||||
SculptVertRef initial_vertex;
|
||||
|
||||
/* Vertex that at max_propagation_steps from the boundary and closest to the original active
|
||||
* vertex that was used to initialize the boundary. This is used as a reference to check how much
|
||||
* the deformation will go into the mesh and to calculate the strength of the brushes. */
|
||||
int pivot_vertex;
|
||||
SculptVertRef pivot_vertex;
|
||||
|
||||
/* Stores the initial positions of the pivot and boundary initial vertex as they may be deformed
|
||||
* during the brush action. This allows to use them as a reference positions and vectors for some
|
||||
@@ -418,7 +445,7 @@ typedef struct SculptBoundary {
|
||||
/* Bend Deform type. */
|
||||
struct {
|
||||
float (*pivot_rotation_axis)[3];
|
||||
float (*pivot_positions)[3];
|
||||
float (*pivot_positions)[4];
|
||||
} bend;
|
||||
|
||||
/* Slide Deform type. */
|
||||
@@ -440,7 +467,7 @@ typedef struct SculptFakeNeighbors {
|
||||
float current_max_distance;
|
||||
|
||||
/* Indexed by vertex, stores the vertex index of its fake neighbor if available. */
|
||||
int *fake_neighbor_index;
|
||||
SculptVertRef *fake_neighbor_index;
|
||||
|
||||
} SculptFakeNeighbors;
|
||||
|
||||
@@ -459,8 +486,15 @@ typedef struct SculptSession {
|
||||
|
||||
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
|
||||
struct MVert *mvert;
|
||||
struct MPoly *mpoly;
|
||||
struct MEdge *medge;
|
||||
struct MLoop *mloop;
|
||||
struct MPoly *mpoly;
|
||||
|
||||
// only assigned in PBVH_FACES and PBVH_GRIDS
|
||||
CustomData *vdata, *edata, *ldata, *pdata;
|
||||
|
||||
// for grids
|
||||
CustomData temp_vdata, temp_pdata;
|
||||
|
||||
/* These contain the vertex and poly counts of the final mesh. */
|
||||
int totvert, totpoly;
|
||||
@@ -495,8 +529,13 @@ typedef struct SculptSession {
|
||||
|
||||
/* BMesh for dynamic topology sculpting */
|
||||
struct BMesh *bm;
|
||||
int cd_dyn_vert;
|
||||
int cd_vert_node_offset;
|
||||
int cd_face_node_offset;
|
||||
int cd_vcol_offset;
|
||||
int cd_faceset_offset;
|
||||
int cd_face_areas;
|
||||
|
||||
bool bm_smooth_shading;
|
||||
/* Undo/redo log for dynamic topology sculpting */
|
||||
struct BMLog *bm_log;
|
||||
@@ -524,9 +563,9 @@ typedef struct SculptSession {
|
||||
struct ExpandCache *expand_cache;
|
||||
|
||||
/* Cursor data and active vertex for tools */
|
||||
int active_vertex_index;
|
||||
SculptVertRef active_vertex_index;
|
||||
SculptFaceRef active_face_index;
|
||||
|
||||
int active_face_index;
|
||||
int active_grid_index;
|
||||
|
||||
/* When active, the cursor draws with faded colors, indicating that there is an action enabled.
|
||||
@@ -548,9 +587,12 @@ typedef struct SculptSession {
|
||||
struct RegionView3D *rv3d;
|
||||
struct View3D *v3d;
|
||||
struct Scene *scene;
|
||||
int cd_origvcol_offset;
|
||||
int cd_origco_offset;
|
||||
int cd_origno_offset;
|
||||
|
||||
/* Dynamic mesh preview */
|
||||
int *preview_vert_index_list;
|
||||
SculptVertRef *preview_vert_index_list;
|
||||
int preview_vert_index_count;
|
||||
|
||||
/* Pose Brush Preview */
|
||||
@@ -612,6 +654,13 @@ typedef struct SculptSession {
|
||||
*/
|
||||
char needs_flush_to_id;
|
||||
|
||||
// id of current stroke, used to detect
|
||||
// if vertex original data needs to be updated
|
||||
int stroke_id, boundary_symmetry;
|
||||
|
||||
bool fast_draw; // hides facesets/masks and forces smooth to save GPU bandwidth
|
||||
struct MDynTopoVert *mdyntopo_verts; // for non-bmesh
|
||||
int mdyntopo_verts_size;
|
||||
} SculptSession;
|
||||
|
||||
void BKE_sculptsession_free(struct Object *ob);
|
||||
@@ -619,6 +668,7 @@ void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
|
||||
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
|
||||
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
|
||||
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
|
||||
bool BKE_sculptsession_check_mdyntopo(SculptSession *ss, int totvert);
|
||||
|
||||
/* Create new color layer on object if it doesn't have one and if experimental feature set has
|
||||
* sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise. */
|
||||
@@ -655,6 +705,8 @@ void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object
|
||||
|
||||
bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d);
|
||||
|
||||
char BKE_get_fset_boundary_symflag(struct Object *object);
|
||||
|
||||
enum {
|
||||
SCULPT_MASK_LAYER_CALC_VERT = (1 << 0),
|
||||
SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1),
|
||||
|
@@ -22,20 +22,97 @@
|
||||
*/
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_ghash.h"
|
||||
|
||||
/* For embedding CCGKey in iterator. */
|
||||
#include "BKE_ccg.h"
|
||||
#include <stdint.h>
|
||||
|
||||
//#define DEFRAGMENT_MEMORY
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// experimental feature to detect quad diagonals and mark (but not dissolve) them
|
||||
//#define SCULPT_DIAGONAL_EDGE_MARKS
|
||||
|
||||
typedef struct SculptVertRef {
|
||||
intptr_t i;
|
||||
} SculptVertRef;
|
||||
|
||||
typedef struct SculptEdgeRef {
|
||||
intptr_t i;
|
||||
} SculptEdgeRef;
|
||||
|
||||
typedef struct SculptFaceRef {
|
||||
intptr_t i;
|
||||
} SculptFaceRef;
|
||||
|
||||
#if 0
|
||||
typedef struct SculptLoopRef {
|
||||
intptr_t i;
|
||||
} SculptLoopRef;
|
||||
#endif
|
||||
|
||||
BLI_INLINE SculptVertRef BKE_pbvh_make_vref(intptr_t i)
|
||||
{
|
||||
SculptVertRef ret = {i};
|
||||
return ret;
|
||||
}
|
||||
|
||||
BLI_INLINE SculptEdgeRef BKE_pbvh_make_eref(intptr_t i)
|
||||
{
|
||||
SculptEdgeRef ret = {i};
|
||||
return ret;
|
||||
}
|
||||
|
||||
BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
|
||||
{
|
||||
SculptFaceRef ret = {i};
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SCULPT_REF_NONE ((intptr_t)-1)
|
||||
|
||||
#ifdef DEFRAGMENT_MEMORY
|
||||
# include "BLI_smallhash.h"
|
||||
#endif
|
||||
|
||||
typedef struct PBVHTri {
|
||||
int v[3]; // references into PBVHTriBuf->verts
|
||||
intptr_t l[3]; // loops
|
||||
int eflag; // bitmask of which edges in the tri are real edges in the mesh
|
||||
|
||||
float no[3];
|
||||
SculptFaceRef f;
|
||||
} PBVHTri;
|
||||
|
||||
typedef struct PBVHTriBuf {
|
||||
PBVHTri *tris;
|
||||
SculptVertRef *verts;
|
||||
int *edges;
|
||||
int totvert, totedge, tottri;
|
||||
int verts_size, edges_size, tris_size;
|
||||
|
||||
SmallHash vertmap; // maps vertex ptrs to indices within verts
|
||||
|
||||
// private field
|
||||
intptr_t *loops;
|
||||
int totloop, mat_nr;
|
||||
float min[3], max[3];
|
||||
} PBVHTriBuf;
|
||||
|
||||
struct BMLog;
|
||||
struct BMesh;
|
||||
struct BMVert;
|
||||
struct BMEdge;
|
||||
struct BMFace;
|
||||
struct CCGElem;
|
||||
struct CCGKey;
|
||||
struct CustomData;
|
||||
struct TableGSet;
|
||||
struct DMFlagMat;
|
||||
struct GPU_PBVH_Buffers;
|
||||
struct IsectRayPrecalc;
|
||||
@@ -52,12 +129,86 @@ struct TaskParallelSettings;
|
||||
typedef struct PBVH PBVH;
|
||||
typedef struct PBVHNode PBVHNode;
|
||||
|
||||
//#define PROXY_ADVANCED
|
||||
|
||||
// experimental performance test of "data-based programming" approach
|
||||
#ifdef PROXY_ADVANCED
|
||||
typedef struct ProxyKey {
|
||||
int node;
|
||||
int pindex;
|
||||
} ProxyKey;
|
||||
|
||||
# define MAX_PROXY_NEIGHBORS 12
|
||||
|
||||
typedef struct ProxyVertArray {
|
||||
float **ownerco;
|
||||
short **ownerno;
|
||||
float (*co)[3];
|
||||
float (*fno)[3];
|
||||
short (*no)[3];
|
||||
float *mask, **ownermask;
|
||||
SculptVertRef *index;
|
||||
float **ownercolor, (*color)[4];
|
||||
|
||||
ProxyKey (*neighbors)[MAX_PROXY_NEIGHBORS];
|
||||
|
||||
int size;
|
||||
int datamask;
|
||||
bool neighbors_dirty;
|
||||
|
||||
GHash *indexmap;
|
||||
} ProxyVertArray;
|
||||
|
||||
typedef enum {
|
||||
PV_OWNERCO = 1,
|
||||
PV_OWNERNO = 2,
|
||||
PV_CO = 4,
|
||||
PV_NO = 8,
|
||||
PV_MASK = 16,
|
||||
PV_OWNERMASK = 32,
|
||||
PV_INDEX = 64,
|
||||
PV_OWNERCOLOR = 128,
|
||||
PV_COLOR = 256,
|
||||
PV_NEIGHBORS = 512
|
||||
} ProxyVertField;
|
||||
|
||||
typedef struct ProxyVertUpdateRec {
|
||||
float *co, *no, *mask, *color;
|
||||
SculptVertRef index, newindex;
|
||||
} ProxyVertUpdateRec;
|
||||
|
||||
# define PBVH_PROXY_DEFAULT CO | INDEX | MASK
|
||||
|
||||
struct SculptSession;
|
||||
|
||||
void BKE_pbvh_ensure_proxyarrays(
|
||||
struct SculptSession *ss, PBVH *pbvh, PBVHNode **nodes, int totnode, int mask);
|
||||
void BKE_pbvh_load_proxyarrays(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask);
|
||||
|
||||
void BKE_pbvh_ensure_proxyarray(
|
||||
struct SculptSession *ss,
|
||||
struct PBVH *pbvh,
|
||||
struct PBVHNode *node,
|
||||
int mask,
|
||||
struct GHash
|
||||
*vert_node_map, // vert_node_map maps vertex SculptVertRefs to PBVHNode indices; optional
|
||||
bool check_indexmap,
|
||||
bool force_update);
|
||||
void BKE_pbvh_gather_proxyarray(PBVH *pbvh, PBVHNode **nodes, int totnode);
|
||||
|
||||
void BKE_pbvh_free_proxyarray(struct PBVH *pbvh, struct PBVHNode *node);
|
||||
void BKE_pbvh_update_proxyvert(struct PBVH *pbvh, struct PBVHNode *node, ProxyVertUpdateRec *rec);
|
||||
ProxyVertArray *BKE_pbvh_get_proxyarrays(struct PBVH *pbvh, struct PBVHNode *node);
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
float (*co)[3];
|
||||
} PBVHProxyNode;
|
||||
|
||||
typedef struct {
|
||||
float (*color)[4];
|
||||
int size;
|
||||
} PBVHColorBufferNode;
|
||||
|
||||
typedef enum {
|
||||
@@ -78,6 +229,15 @@ typedef enum {
|
||||
|
||||
PBVH_UpdateTopology = 1 << 13,
|
||||
PBVH_UpdateColor = 1 << 14,
|
||||
PBVH_Delete = 1 << 15,
|
||||
PBVH_UpdateCurvatureDir = 1 << 16,
|
||||
PBVH_UpdateTris = 1 << 17,
|
||||
PBVH_RebuildNodeVerts = 1 << 18,
|
||||
|
||||
/* tri areas are not guaranteed to be up to date, tools should
|
||||
update all nodes on first step of brush*/
|
||||
PBVH_UpdateTriAreas = 1 << 19,
|
||||
PBVH_UpdateOtherVerts = 1 << 20
|
||||
} PBVHNodeFlags;
|
||||
|
||||
typedef struct PBVHFrustumPlanes {
|
||||
@@ -98,6 +258,9 @@ typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *
|
||||
|
||||
typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float *tmin);
|
||||
|
||||
void BKE_pbvh_get_nodes(PBVH *pbvh, int flag, PBVHNode ***r_array, int *r_totnode);
|
||||
PBVHNode *BKE_pbvh_get_node(PBVH *pbvh, int node);
|
||||
|
||||
/* Building */
|
||||
|
||||
PBVH *BKE_pbvh_new(void);
|
||||
@@ -106,27 +269,57 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
|
||||
const struct MPoly *mpoly,
|
||||
const struct MLoop *mloop,
|
||||
struct MVert *verts,
|
||||
struct MDynTopoVert *mdyntopo_verts,
|
||||
int totvert,
|
||||
struct CustomData *vdata,
|
||||
struct CustomData *ldata,
|
||||
struct CustomData *pdata,
|
||||
const struct MLoopTri *looptri,
|
||||
int looptri_num);
|
||||
int looptri_num,
|
||||
bool fast_draw);
|
||||
void BKE_pbvh_build_grids(PBVH *pbvh,
|
||||
struct CCGElem **grids,
|
||||
int totgrid,
|
||||
struct CCGKey *key,
|
||||
void **gridfaces,
|
||||
struct DMFlagMat *flagmats,
|
||||
unsigned int **grid_hidden);
|
||||
unsigned int **grid_hidden,
|
||||
bool fast_draw);
|
||||
void BKE_pbvh_build_bmesh(PBVH *pbvh,
|
||||
struct BMesh *bm,
|
||||
bool smooth_shading,
|
||||
struct BMLog *log,
|
||||
const int cd_vert_node_offset,
|
||||
const int cd_face_node_offset);
|
||||
const int cd_face_node_offset,
|
||||
const int cd_dyn_vert,
|
||||
const int cd_face_areas,
|
||||
bool fast_draw);
|
||||
void BKE_pbvh_update_offsets(PBVH *pbvh,
|
||||
const int cd_vert_node_offset,
|
||||
const int cd_face_node_offset,
|
||||
const int cd_dyn_vert,
|
||||
const int cd_face_areas);
|
||||
void BKE_pbvh_free(PBVH *pbvh);
|
||||
|
||||
void BKE_pbvh_set_bm_log(PBVH *pbvh, struct BMLog *log);
|
||||
|
||||
/** update original data, only data whose r_** parameters are passed in will be updated*/
|
||||
void BKE_pbvh_bmesh_update_origvert(
|
||||
PBVH *pbvh, struct BMVert *v, float **r_co, float **r_no, float **r_color, bool log_undo);
|
||||
void BKE_pbvh_update_origcolor_bmesh(PBVH *pbvh, PBVHNode *node);
|
||||
void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node);
|
||||
|
||||
/**
|
||||
checks if original data needs to be updated for v, and if so updates it. Stroke_id
|
||||
is provided by the sculpt code and is used to detect updates. The reason we do it
|
||||
inside the verts and not in the nodes is to allow splitting of the pbvh during the stroke.
|
||||
*/
|
||||
bool BKE_pbvh_bmesh_check_origdata(PBVH *pbvh, struct BMVert *v, int stroke_id);
|
||||
|
||||
/** used so pbvh can differentiate between different strokes,
|
||||
see BKE_pbvh_bmesh_check_origdata */
|
||||
void BKE_pbvh_set_stroke_id(PBVH *pbvh, int stroke_id);
|
||||
|
||||
/* Hierarchical Search in the BVH, two methods:
|
||||
* - for each hit calling a callback
|
||||
* - gather nodes in an array (easy to multithread) */
|
||||
@@ -150,7 +343,8 @@ void BKE_pbvh_raycast(PBVH *pbvh,
|
||||
void *data,
|
||||
const float ray_start[3],
|
||||
const float ray_normal[3],
|
||||
bool original);
|
||||
bool original,
|
||||
int stroke_id);
|
||||
|
||||
bool BKE_pbvh_node_raycast(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
@@ -160,11 +354,13 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
|
||||
const float ray_normal[3],
|
||||
struct IsectRayPrecalc *isect_precalc,
|
||||
float *depth,
|
||||
int *active_vertex_index,
|
||||
int *active_face_grid_index,
|
||||
float *face_normal);
|
||||
SculptVertRef *active_vertex_index,
|
||||
SculptFaceRef *active_face_grid_index,
|
||||
float *face_normal,
|
||||
int stroke_id);
|
||||
|
||||
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
|
||||
bool BKE_pbvh_bmesh_node_raycast_detail(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
const float ray_start[3],
|
||||
struct IsectRayPrecalc *isect_precalc,
|
||||
float *depth,
|
||||
@@ -189,7 +385,8 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
|
||||
const float ray_start[3],
|
||||
const float ray_normal[3],
|
||||
float *depth,
|
||||
float *dist_sq);
|
||||
float *dist_sq,
|
||||
int stroke_id);
|
||||
|
||||
/* Drawing */
|
||||
|
||||
@@ -238,22 +435,60 @@ int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh);
|
||||
|
||||
/* Only valid for type == PBVH_BMESH */
|
||||
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
|
||||
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
|
||||
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size, float detail_range);
|
||||
|
||||
typedef enum {
|
||||
PBVH_Subdivide = 1,
|
||||
PBVH_Collapse = 2,
|
||||
PBVH_Subdivide = 1 << 0,
|
||||
PBVH_Collapse = 1 << 1,
|
||||
PBVH_Cleanup = 1 << 2, // dissolve verts surrounded by either 3 or 4 triangles then triangulate
|
||||
PBVH_LocalSubdivide = 1 << 3,
|
||||
PBVH_LocalCollapse = 1 << 4
|
||||
} PBVHTopologyUpdateMode;
|
||||
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
||||
PBVHTopologyUpdateMode mode,
|
||||
const float center[3],
|
||||
const float view_normal[3],
|
||||
float radius,
|
||||
const bool use_frontface,
|
||||
const bool use_projected);
|
||||
|
||||
typedef float (*DyntopoMaskCB)(SculptVertRef vertex, void *userdata);
|
||||
|
||||
bool BKE_pbvh_bmesh_update_topology(
|
||||
PBVH *pbvh,
|
||||
PBVHTopologyUpdateMode mode,
|
||||
const float center[3],
|
||||
const float view_normal[3],
|
||||
float radius,
|
||||
const bool use_frontface,
|
||||
const bool use_projected,
|
||||
int symaxis,
|
||||
bool updatePBVH,
|
||||
DyntopoMaskCB mask_cb,
|
||||
void *mask_cb_data,
|
||||
int custom_max_steps); // if 0, will use defaul hueristics for max steps
|
||||
|
||||
bool BKE_pbvh_bmesh_update_topology_nodes(PBVH *pbvh,
|
||||
bool (*searchcb)(PBVHNode *node, void *data),
|
||||
void (*undopush)(PBVHNode *node, void *data),
|
||||
void *searchdata,
|
||||
PBVHTopologyUpdateMode mode,
|
||||
const float center[3],
|
||||
const float view_normal[3],
|
||||
float radius,
|
||||
const bool use_frontface,
|
||||
const bool use_projected,
|
||||
int sym_axis,
|
||||
bool updatePBVH,
|
||||
DyntopoMaskCB mask_cb,
|
||||
void *mask_cb_data);
|
||||
/* Node Access */
|
||||
|
||||
void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node);
|
||||
|
||||
// updates boundaries and valences for whole mesh
|
||||
void BKE_pbvh_bmesh_on_mesh_change(PBVH *pbvh);
|
||||
bool BKE_pbvh_bmesh_check_valence(PBVH *pbvh, SculptVertRef vertex);
|
||||
void BKE_pbvh_bmesh_update_valence(int cd_dyn_vert, SculptVertRef vertex);
|
||||
void BKE_pbvh_bmesh_update_all_valence(PBVH *pbvh);
|
||||
void BKE_pbvh_bmesh_flag_all_disk_sort(PBVH *pbvh);
|
||||
bool BKE_pbvh_bmesh_mark_update_valence(PBVH *pbvh, SculptVertRef vertex);
|
||||
|
||||
void BKE_pbvh_node_mark_update_tri_area(PBVHNode *node);
|
||||
void BKE_pbvh_update_all_tri_areas(PBVH *pbvh);
|
||||
void BKE_pbvh_node_mark_update(PBVHNode *node);
|
||||
void BKE_pbvh_node_mark_update_mask(PBVHNode *node);
|
||||
void BKE_pbvh_node_mark_update_color(PBVHNode *node);
|
||||
@@ -292,10 +527,14 @@ bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
|
||||
/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
|
||||
bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
|
||||
|
||||
struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
|
||||
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
|
||||
struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
|
||||
void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
|
||||
struct TableGSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
|
||||
struct TableGSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
|
||||
struct TableGSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
|
||||
|
||||
void BKE_pbvh_bmesh_regen_node_verts(PBVH *pbvh);
|
||||
void BKE_pbvh_bmesh_mark_node_regen(PBVH *pbvh, PBVHNode *node);
|
||||
|
||||
// now generated PBVHTris
|
||||
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
|
||||
|
||||
/* Update Bounding Box/Redraw and clear flags */
|
||||
@@ -343,6 +582,7 @@ typedef struct PBVHVertexIter {
|
||||
int gy;
|
||||
int i;
|
||||
int index;
|
||||
SculptVertRef vertex;
|
||||
bool respect_hide;
|
||||
|
||||
/* grid */
|
||||
@@ -362,10 +602,14 @@ typedef struct PBVHVertexIter {
|
||||
float *vmask;
|
||||
|
||||
/* bmesh */
|
||||
struct GSetIterator bm_unique_verts;
|
||||
struct GSetIterator bm_other_verts;
|
||||
int bi;
|
||||
struct TableGSet *bm_cur_set;
|
||||
struct TableGSet *bm_unique_verts, *bm_other_verts;
|
||||
|
||||
struct CustomData *bm_vdata;
|
||||
int cd_dyn_vert;
|
||||
int cd_vert_mask_offset;
|
||||
int cd_vcol_offset;
|
||||
|
||||
/* result: these are all computed in the macro, but we assume
|
||||
* that compiler optimization's will skip the ones we don't use */
|
||||
@@ -379,6 +623,8 @@ typedef struct PBVHVertexIter {
|
||||
bool visible;
|
||||
} PBVHVertexIter;
|
||||
|
||||
#define BKE_PBVH_DYNVERT(cd_dyn_vert, v) ((MDynTopoVert *)BM_ELEM_CD_GET_VOID_P(v, cd_dyn_vert))
|
||||
|
||||
void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode);
|
||||
|
||||
#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode) \
|
||||
@@ -388,7 +634,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
||||
if (vi.grids) { \
|
||||
vi.width = vi.gridsize; \
|
||||
vi.height = vi.gridsize; \
|
||||
vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
|
||||
vi.vertex.i = vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
|
||||
vi.grid = vi.grids[vi.grid_indices[vi.g]]; \
|
||||
if (mode == PBVH_ITER_UNIQUE) { \
|
||||
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
|
||||
@@ -407,6 +653,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
||||
vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \
|
||||
vi.grid = CCG_elem_next(&vi.key, vi.grid); \
|
||||
vi.index++; \
|
||||
vi.vertex.i++; \
|
||||
vi.visible = true; \
|
||||
if (vi.gh) { \
|
||||
if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) { \
|
||||
@@ -427,7 +674,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
||||
} \
|
||||
vi.co = vi.mvert->co; \
|
||||
vi.no = vi.mvert->no; \
|
||||
vi.index = vi.vert_indices[vi.i]; \
|
||||
vi.index = vi.vertex.i = vi.vert_indices[vi.i]; \
|
||||
if (vi.vmask) { \
|
||||
vi.mask = &vi.vmask[vi.index]; \
|
||||
} \
|
||||
@@ -436,22 +683,41 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
if (!BLI_gsetIterator_done(&vi.bm_unique_verts)) { \
|
||||
vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_unique_verts); \
|
||||
BLI_gsetIterator_step(&vi.bm_unique_verts); \
|
||||
BMVert *bv = NULL; \
|
||||
while (!bv) { \
|
||||
if (!vi.bm_cur_set->elems || vi.bi >= vi.bm_cur_set->cur) { \
|
||||
if (vi.bm_cur_set != vi.bm_other_verts && mode != PBVH_ITER_UNIQUE) { \
|
||||
vi.bm_cur_set = vi.bm_other_verts; \
|
||||
vi.bi = 0; \
|
||||
if (!vi.bm_cur_set->elems || vi.bi >= vi.bm_other_verts->cur) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
bv = vi.bm_cur_set->elems[vi.bi++]; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_other_verts); \
|
||||
BLI_gsetIterator_step(&vi.bm_other_verts); \
|
||||
if (!bv) { \
|
||||
continue; \
|
||||
} \
|
||||
vi.bm_vert = bv; \
|
||||
if (vi.cd_vcol_offset >= 0) { \
|
||||
MPropCol *vcol = BM_ELEM_CD_GET_VOID_P(bv, vi.cd_vcol_offset); \
|
||||
vi.col = vcol->color; \
|
||||
} \
|
||||
vi.vertex.i = (intptr_t)bv; \
|
||||
vi.index = BM_elem_index_get(vi.bm_vert); \
|
||||
vi.visible = !BM_elem_flag_test_bool(vi.bm_vert, BM_ELEM_HIDDEN); \
|
||||
if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
|
||||
continue; \
|
||||
} \
|
||||
vi.co = vi.bm_vert->co; \
|
||||
vi.fno = vi.bm_vert->no; \
|
||||
vi.index = BM_elem_index_get(vi.bm_vert); \
|
||||
vi.mask = BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
|
||||
vi.mask = (float *)BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
|
||||
}
|
||||
|
||||
#define BKE_pbvh_vertex_iter_end \
|
||||
@@ -460,24 +726,28 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
||||
} \
|
||||
((void)0)
|
||||
|
||||
#define BKE_pbvh_vertex_index_to_table(pbvh, v) \
|
||||
(BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != -1 ? BM_elem_index_get((BMVert *)(v.i)) : (v.i))
|
||||
SculptVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int idx);
|
||||
|
||||
#define BKE_pbvh_face_index_to_table(pbvh, v) \
|
||||
(BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != -1 ? BM_elem_index_get((BMFace *)(v.i)) : (v.i))
|
||||
SculptFaceRef BKE_pbvh_table_index_to_face(PBVH *pbvh, int idx);
|
||||
|
||||
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count);
|
||||
void BKE_pbvh_node_free_proxies(PBVHNode *node);
|
||||
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node);
|
||||
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot);
|
||||
void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
|
||||
int (**r_orco_tris)[3],
|
||||
int *r_orco_tris_num,
|
||||
float (**r_orco_coords)[3]);
|
||||
|
||||
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
|
||||
|
||||
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
|
||||
// void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
|
||||
|
||||
bool pbvh_has_mask(const PBVH *pbvh);
|
||||
bool BKE_pbvh_draw_mask(const PBVH *pbvh);
|
||||
void pbvh_show_mask_set(PBVH *pbvh, bool show_mask);
|
||||
|
||||
bool pbvh_has_face_sets(PBVH *pbvh);
|
||||
bool BKE_pbvh_draw_face_sets(PBVH *pbvh);
|
||||
void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets);
|
||||
|
||||
/* Parallelization */
|
||||
@@ -490,6 +760,150 @@ struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh);
|
||||
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
|
||||
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
|
||||
|
||||
int BKE_pbvh_get_node_index(PBVH *pbvh, PBVHNode *node);
|
||||
int BKE_pbvh_get_node_id(PBVH *pbvh, PBVHNode *node);
|
||||
void BKE_pbvh_set_flat_vcol_shading(PBVH *pbvh, bool value);
|
||||
|
||||
#define DYNTOPO_CD_INTERP
|
||||
|
||||
void SCULPT_update_flat_vcol_shading(struct Object *ob, struct Scene *scene);
|
||||
|
||||
void BKE_pbvh_curvature_update_set(PBVHNode *node, bool state);
|
||||
bool BKE_pbvh_curvature_update_get(PBVHNode *node);
|
||||
|
||||
int BKE_pbvh_get_totnodes(PBVH *pbvh);
|
||||
|
||||
bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node);
|
||||
PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node);
|
||||
void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node);
|
||||
|
||||
/*recalculates boundary flags for *all* vertices. used by
|
||||
symmetrize.*/
|
||||
void BKE_pbvh_recalc_bmesh_boundary(PBVH *pbvh);
|
||||
|
||||
void BKE_pbvh_bmesh_remove_face(PBVH *pbvh, struct BMFace *f, bool log_face);
|
||||
void BKE_pbvh_bmesh_remove_vertex(PBVH *pbvh, struct BMVert *v, bool log_vert);
|
||||
void BKE_pbvh_bmesh_add_face(PBVH *pbvh, struct BMFace *f, bool log_face, bool force_tree_walk);
|
||||
|
||||
// note that e_tri and f_example are allowed to be NULL
|
||||
struct BMFace *BKE_pbvh_face_create_bmesh(PBVH *pbvh,
|
||||
struct BMVert *v_tri[3],
|
||||
struct BMEdge *e_tri[3],
|
||||
const struct BMFace *f_example);
|
||||
|
||||
// if node is NULL, one will be foudn in the pbvh, which potentially can be slow
|
||||
struct BMVert *BKE_pbvh_vert_create_bmesh(
|
||||
PBVH *pbvh, float co[3], float no[3], PBVHNode *node, struct BMVert *v_example);
|
||||
PBVHNode *BKE_pbvh_node_from_face_bmesh(PBVH *pbvh, struct BMFace *f);
|
||||
PBVHNode *BKE_pbvh_node_from_index(PBVH *pbvh, int node_i);
|
||||
|
||||
struct BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh);
|
||||
void BKE_pbvh_update_vert_boundary(int cd_dyn_vert,
|
||||
int cd_faceset_offset,
|
||||
struct BMVert *v,
|
||||
int symmetry);
|
||||
|
||||
#define DYNTOPO_DYNAMIC_TESS
|
||||
|
||||
PBVHNode *BKE_pbvh_get_node_leaf_safe(PBVH *pbvh, int i);
|
||||
|
||||
void BKE_pbvh_get_vert_face_areas(PBVH *pbvh, SculptVertRef vertex, float *r_areas, int valence);
|
||||
void BKE_pbvh_set_symmetry(PBVH *pbvh, int symmetry, int boundary_symmetry);
|
||||
|
||||
#if 0
|
||||
typedef enum {
|
||||
SCULPT_TEXTURE_UV = 1 << 0, // per-uv
|
||||
// SCULPT_TEXTURE_PTEX?
|
||||
} SculptTextureType;
|
||||
|
||||
typedef int TexLayerRef;
|
||||
|
||||
/*
|
||||
Texture points are texels projected into 3d.
|
||||
*/
|
||||
typedef intptr_t TexPointRef;
|
||||
|
||||
void *BKE_pbvh_get_tex_settings(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
|
||||
void *BKE_pbvh_get_tex_data(PBVH *pbvh, PBVHNode *node, TexPointRef vdm);
|
||||
|
||||
typedef struct SculptTextureDef {
|
||||
SculptTextureType type;
|
||||
int settings_size;
|
||||
|
||||
void (*build_begin)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
|
||||
|
||||
/*vdms can cache data per node, which is freed to maintain memory limit.
|
||||
they store cache in the same structure they return in buildNodeData.*/
|
||||
void (*freeCachedData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
|
||||
void (*ensuredCachedData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
|
||||
|
||||
/*builds all data that isn't cached.*/
|
||||
void *(*buildNodeData)(PBVH *pbvh, PBVHNode *node);
|
||||
bool (*validate)(PBVH *pbvh, TexLayerRef vdm);
|
||||
|
||||
void (*getPointsFromNode)(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
TexLayerRef vdm,
|
||||
TexPointRef **r_ids,
|
||||
float ***r_cos,
|
||||
float ***r_nos,
|
||||
int *r_totpoint);
|
||||
void (*releaseNodePoints)(
|
||||
PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, float **cos, float **nos);
|
||||
|
||||
# if 0
|
||||
int (*getTrisFromNode)(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
TexLayerRef vdm,
|
||||
TexPointRef *((*r_tris)[3]),
|
||||
TexPointRef **r_ids,
|
||||
int tottri,
|
||||
int totid);
|
||||
void (*getTriInterpWeightsFromNode)(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
TexLayerRef vdm,
|
||||
float *((*r_tris)[3]),
|
||||
SculptLoopRef ***r_src_loops,
|
||||
int tottri,
|
||||
int totloop);
|
||||
int (*getTriCount)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
|
||||
# endif
|
||||
|
||||
void (*getPointNeighbors)(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
TexLayerRef vdm,
|
||||
TexPointRef id,
|
||||
TexPointRef **r_neighbor_ids,
|
||||
int *r_totneighbor,
|
||||
int maxneighbors,
|
||||
TexPointRef **r_duplicates_id,
|
||||
int r_totduplicate,
|
||||
int maxduplicates);
|
||||
void (*getPointValence)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef id);
|
||||
void (*freeNodeData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, void *settings);
|
||||
|
||||
void (*getPointsFromIds)(
|
||||
PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
|
||||
|
||||
/*displacement texture stuff*/
|
||||
// can be tangent, object space displacement, whatever
|
||||
void (*worldToDelta)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
|
||||
void (*deltaToWorld)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
|
||||
} SculptDisplacementDef;
|
||||
|
||||
typedef struct SculptLayerEntry {
|
||||
char name[64];
|
||||
int type;
|
||||
void *settings;
|
||||
float factor;
|
||||
struct SculptLayerEntry *parent;
|
||||
} SculptLayerEntry;
|
||||
|
||||
#endif
|
||||
|
||||
int BKE_pbvh_do_fset_symmetry(int fset, const int symflag, const float *co);
|
||||
bool BKE_pbvh_check_vert_boundary(PBVH *pbvh, struct BMVert *v);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -124,6 +124,7 @@ set(SRC
|
||||
intern/displist.cc
|
||||
intern/displist_tangent.c
|
||||
intern/dynamicpaint.c
|
||||
intern/dyntopo.c
|
||||
intern/editlattice.c
|
||||
intern/editmesh.c
|
||||
intern/editmesh_bvh.c
|
||||
@@ -235,6 +236,7 @@ set(SRC
|
||||
intern/particle_system.c
|
||||
intern/pbvh.c
|
||||
intern/pbvh_bmesh.c
|
||||
intern/pbvh_displacement.c
|
||||
intern/pointcache.c
|
||||
intern/pointcloud.cc
|
||||
intern/preferences.c
|
||||
@@ -287,6 +289,7 @@ set(SRC
|
||||
intern/workspace.c
|
||||
intern/world.c
|
||||
intern/writeavi.c
|
||||
intern/brush_engine.c
|
||||
|
||||
BKE_DerivedMesh.h
|
||||
BKE_action.h
|
||||
@@ -449,6 +452,7 @@ set(SRC
|
||||
BKE_workspace.h
|
||||
BKE_world.h
|
||||
BKE_writeavi.h
|
||||
BKE_brush_engine.h
|
||||
|
||||
nla_private.h
|
||||
particle_private.h
|
||||
@@ -794,3 +798,75 @@ if(WITH_GTESTS)
|
||||
include(GTestTesting)
|
||||
blender_add_test_lib(bf_blenkernel_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB}")
|
||||
endif()
|
||||
|
||||
if(false)
|
||||
set(PBVH_CACHE_TEST_INC
|
||||
.
|
||||
../blenfont
|
||||
../blenlib
|
||||
../blenloader
|
||||
../blentranslation
|
||||
../bmesh
|
||||
../depsgraph
|
||||
../draw
|
||||
../functions
|
||||
../gpencil_modifiers
|
||||
../gpu
|
||||
../ikplugin
|
||||
../imbuf
|
||||
../makesdna
|
||||
../makesrna
|
||||
../modifiers
|
||||
../nodes
|
||||
../render
|
||||
../sequencer
|
||||
../shader_fx
|
||||
../simulation
|
||||
../../../intern/eigen
|
||||
../../../intern/ghost
|
||||
../../../intern/glew-mx
|
||||
../../../intern/guardedalloc
|
||||
../../../intern/iksolver/extern
|
||||
../../../intern/atomic
|
||||
../../../intern/clog
|
||||
../../../intern/libmv
|
||||
../../../intern/mantaflow/extern
|
||||
../../../intern/memutil
|
||||
../../../intern/mikktspace
|
||||
../../../intern/opensubdiv
|
||||
../../../extern/curve_fit_nd
|
||||
)
|
||||
|
||||
set(PBVH_CACHE_TEST_SRC
|
||||
intern/pbvh_cache_test_main.c
|
||||
)
|
||||
|
||||
setup_libdirs()
|
||||
|
||||
add_executable(pbvh_cache_test ${PBVH_CACHE_TEST_SRC} ${PBVH_CACHE_TEST_INC})
|
||||
setup_platform_linker_flags(pbvh_cache_test)
|
||||
|
||||
target_link_libraries(pbvh_cache_test bf_blenkernel bf_bmesh bf_intern_ghost bf_blenlib bf_intern_guardedalloc)
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(pbvh_cache_test PROPERTIES VS_GLOBAL_VcpkgEnabled "false")
|
||||
set_target_properties(pbvh_cache_test PROPERTIES
|
||||
PDB_NAME "pbvh_cache_test_private"
|
||||
PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
|
||||
if(WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB)
|
||||
# This is slightly messy, but single target generators like ninja will not have the
|
||||
# CMAKE_CFG_INTDIR variable and multitarget generators like msbuild will not have
|
||||
# CMAKE_BUILD_TYPE. This can be simplified by target_link_options and the $<CONFIG>
|
||||
# generator expression in newer cmake (2.13+) but until that time this fill have suffice.
|
||||
if(CMAKE_BUILD_TYPE)
|
||||
set_property(TARGET pbvh_cache_test APPEND_STRING PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/pbvh_cache_test_public.pdb")
|
||||
else()
|
||||
set_property(TARGET pbvh_cache_test APPEND_STRING PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/pbvh_cache_test_public.pdb")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(pbvh_cache_test Vfw32.lib Imm32.lib Version.lib Comctl32.lib Shcore.lib Pathcch.lib)
|
||||
endif()
|
||||
endif()
|
||||
|
@@ -1140,7 +1140,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
|
||||
unsupported = true;
|
||||
}
|
||||
|
||||
if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) {
|
||||
if (scene->toolsettings->sculpt && scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) {
|
||||
unsupported |= (mti->type != eModifierTypeType_OnlyDeform);
|
||||
}
|
||||
|
||||
|
@@ -425,7 +425,7 @@ void BKE_animdata_copy_id_action(Main *bmain, ID *id)
|
||||
|
||||
void BKE_animdata_duplicate_id_action(struct Main *bmain,
|
||||
struct ID *id,
|
||||
const eDupli_ID_Flags duplicate_flags)
|
||||
const uint duplicate_flags)
|
||||
{
|
||||
if (duplicate_flags & USER_DUP_ACT) {
|
||||
animdata_copy_id_action(bmain, id, true, (duplicate_flags & USER_DUP_LINKED_ID) != 0);
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BKE_brush.h"
|
||||
#include "BKE_brush_engine.h"
|
||||
#include "BKE_colortools.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_gpencil.h"
|
||||
@@ -262,12 +263,47 @@ static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_addres
|
||||
if (brush->gradient) {
|
||||
BLO_write_struct(writer, ColorBand, brush->gradient);
|
||||
}
|
||||
|
||||
if (brush->channels) {
|
||||
BKE_brush_channelset_write(writer, brush->channels);
|
||||
}
|
||||
}
|
||||
|
||||
static void brush_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
ATTR_NO_OPT static void brush_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
{
|
||||
Brush *brush = (Brush *)id;
|
||||
|
||||
if (brush->channels) {
|
||||
BLO_read_data_address(reader, &brush->channels);
|
||||
BKE_brush_channelset_read(reader, brush->channels);
|
||||
}
|
||||
else {
|
||||
BKE_brush_builtin_create(brush, brush->sculpt_tool);
|
||||
}
|
||||
|
||||
if (brush->dyntopo.radius_scale == 0.0f) {
|
||||
brush->dyntopo.radius_scale = 1.0f;
|
||||
brush->dyntopo.inherit |= DYNTOPO_INHERIT_RADIUS_SCALE;
|
||||
}
|
||||
|
||||
// detect old file data
|
||||
if (brush->autosmooth_radius_factor == 0.0f) {
|
||||
brush->autosmooth_radius_factor = 1.0f;
|
||||
}
|
||||
|
||||
if (brush->topology_rake_radius_factor == 0.0f) {
|
||||
brush->topology_rake_radius_factor = 1.0f;
|
||||
}
|
||||
|
||||
if (brush->autosmooth_spacing == 0.0f) {
|
||||
brush->autosmooth_spacing = 12;
|
||||
}
|
||||
|
||||
if (brush->topology_rake_spacing == 0.0f) {
|
||||
brush->topology_rake_spacing = 12;
|
||||
brush->topology_rake_projection = 1.0f;
|
||||
}
|
||||
|
||||
/* Falloff curve. */
|
||||
BLO_read_data_address(reader, &brush->curve);
|
||||
|
||||
@@ -464,7 +500,13 @@ static void brush_defaults(Brush *brush)
|
||||
FROM_DEFAULT(alpha);
|
||||
FROM_DEFAULT(hardness);
|
||||
FROM_DEFAULT(autosmooth_factor);
|
||||
FROM_DEFAULT(autosmooth_projection);
|
||||
FROM_DEFAULT(autosmooth_radius_factor);
|
||||
FROM_DEFAULT(autosmooth_spacing);
|
||||
FROM_DEFAULT(topology_rake_factor);
|
||||
FROM_DEFAULT(topology_rake_radius_factor);
|
||||
FROM_DEFAULT(topology_rake_projection);
|
||||
FROM_DEFAULT(topology_rake_spacing);
|
||||
FROM_DEFAULT(crease_pinch_factor);
|
||||
FROM_DEFAULT(normal_radius_factor);
|
||||
FROM_DEFAULT(wet_paint_radius_factor);
|
||||
@@ -495,6 +537,7 @@ static void brush_defaults(Brush *brush)
|
||||
FROM_DEFAULT(stencil_dimension);
|
||||
FROM_DEFAULT(mtex);
|
||||
FROM_DEFAULT(mask_mtex);
|
||||
FROM_DEFAULT(dyntopo);
|
||||
|
||||
#undef FROM_DEFAULT
|
||||
#undef FROM_DEFAULT_PTR
|
||||
@@ -1662,6 +1705,8 @@ void BKE_brush_debug_print_state(Brush *br)
|
||||
BR_TEST(plane_offset, f);
|
||||
|
||||
BR_TEST(autosmooth_factor, f);
|
||||
BR_TEST(autosmooth_projection, f);
|
||||
BR_TEST(autosmooth_radius_factor, f);
|
||||
|
||||
BR_TEST(topology_rake_factor, f);
|
||||
|
||||
@@ -1703,6 +1748,12 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
* assign this so logic below can remain the same. */
|
||||
br->alpha = 0.5f;
|
||||
|
||||
bool disable_dyntopo = false;
|
||||
|
||||
// basic face set setup for all organic brushes
|
||||
br->autosmooth_fset_slide = 1.0f;
|
||||
br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT;
|
||||
|
||||
/* Brush settings */
|
||||
switch (br->sculpt_tool) {
|
||||
case SCULPT_TOOL_DRAW_SHARP:
|
||||
@@ -1714,11 +1765,16 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->curve_preset = BRUSH_CURVE_SMOOTHER;
|
||||
br->spacing = 10;
|
||||
br->alpha = 1.0f;
|
||||
|
||||
disable_dyntopo = true;
|
||||
|
||||
break;
|
||||
case SCULPT_TOOL_SLIDE_RELAX:
|
||||
br->spacing = 10;
|
||||
br->alpha = 1.0f;
|
||||
br->slide_deform_type = BRUSH_SLIDE_DEFORM_DRAG;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_CLAY:
|
||||
br->flag |= BRUSH_SIZE_PRESSURE;
|
||||
@@ -1766,18 +1822,29 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
break;
|
||||
case SCULPT_TOOL_ROTATE:
|
||||
br->alpha = 1.0;
|
||||
disable_dyntopo = true;
|
||||
|
||||
break;
|
||||
case SCULPT_TOOL_SMOOTH:
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT;
|
||||
|
||||
br->spacing = 5;
|
||||
br->alpha = 0.7f;
|
||||
br->surface_smooth_shape_preservation = 0.5f;
|
||||
br->surface_smooth_current_vertex = 0.5f;
|
||||
br->surface_smooth_iterations = 4;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_SNAKE_HOOK:
|
||||
br->alpha = 1.0f;
|
||||
br->rake_factor = 1.0f;
|
||||
br->dyntopo.inherit = DYNTOPO_INHERIT_BITMASK &
|
||||
~(DYNTOPO_INHERIT_ALL | DYNTOPO_LOCAL_COLLAPSE |
|
||||
DYNTOPO_INHERIT_DETAIL_RANGE);
|
||||
br->dyntopo.flag |= DYNTOPO_LOCAL_COLLAPSE;
|
||||
br->dyntopo.detail_range = 0.4f;
|
||||
break;
|
||||
case SCULPT_TOOL_THUMB:
|
||||
br->size = 75;
|
||||
@@ -1791,6 +1858,8 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->flag &= ~BRUSH_ALPHA_PRESSURE;
|
||||
br->flag &= ~BRUSH_SPACE;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_POSE:
|
||||
br->pose_smooth_iterations = 4;
|
||||
@@ -1799,18 +1868,24 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->flag &= ~BRUSH_ALPHA_PRESSURE;
|
||||
br->flag &= ~BRUSH_SPACE;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_BOUNDARY:
|
||||
br->flag &= ~BRUSH_ALPHA_PRESSURE;
|
||||
br->flag &= ~BRUSH_SPACE;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
br->curve_preset = BRUSH_CURVE_CONSTANT;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_DRAW_FACE_SETS:
|
||||
br->alpha = 0.5f;
|
||||
br->flag &= ~BRUSH_ALPHA_PRESSURE;
|
||||
br->flag &= ~BRUSH_SPACE;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_GRAB:
|
||||
br->alpha = 0.4f;
|
||||
@@ -1818,6 +1893,8 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->flag &= ~BRUSH_ALPHA_PRESSURE;
|
||||
br->flag &= ~BRUSH_SPACE;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_CLOTH:
|
||||
br->cloth_mass = 1.0f;
|
||||
@@ -1826,6 +1903,8 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->cloth_sim_falloff = 0.75f;
|
||||
br->cloth_deform_type = BRUSH_CLOTH_DEFORM_DRAG;
|
||||
br->flag &= ~(BRUSH_ALPHA_PRESSURE | BRUSH_SIZE_PRESSURE);
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_LAYER:
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
@@ -1843,6 +1922,8 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->density = 1.0f;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
zero_v3(br->rgb);
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_SMEAR:
|
||||
br->alpha = 1.0f;
|
||||
@@ -1850,6 +1931,18 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->flag &= ~BRUSH_ALPHA_PRESSURE;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
br->curve_preset = BRUSH_CURVE_SPHERE;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_VCOL_BOUNDARY:
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
br->spacing = 5;
|
||||
br->alpha = 0.7f;
|
||||
br->surface_smooth_shape_preservation = 0.5f;
|
||||
br->surface_smooth_current_vertex = 0.5f;
|
||||
br->surface_smooth_iterations = 4;
|
||||
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
|
||||
br->alpha = 1.0f;
|
||||
@@ -1858,11 +1951,17 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
br->flag &= ~BRUSH_ALPHA_PRESSURE;
|
||||
br->flag &= ~BRUSH_SPACE_ATTEN;
|
||||
br->curve_preset = BRUSH_CURVE_SMOOTHER;
|
||||
disable_dyntopo = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (disable_dyntopo) {
|
||||
// disabled flag is never inherited
|
||||
br->dyntopo.flag |= DYNTOPO_DISABLED;
|
||||
}
|
||||
|
||||
/* Cursor colors */
|
||||
|
||||
/* Default Alpha */
|
||||
@@ -1919,6 +2018,20 @@ void BKE_brush_sculpt_reset(Brush *br)
|
||||
break;
|
||||
|
||||
case SCULPT_TOOL_SIMPLIFY:
|
||||
// don't use DYNTOPO_INHERIT_BITMASK, we want to include
|
||||
// future bits
|
||||
|
||||
br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT |
|
||||
BRUSH_CURVATURE_RAKE;
|
||||
br->dyntopo.inherit = 0x7FFFFFFF &
|
||||
~(DYNTOPO_INHERIT_ALL | DYNTOPO_SUBDIVIDE | DYNTOPO_COLLAPSE);
|
||||
br->dyntopo.flag |= DYNTOPO_COLLAPSE | DYNTOPO_SUBDIVIDE;
|
||||
br->autosmooth_factor = 0.05;
|
||||
br->topology_rake_factor = 0.35;
|
||||
br->topology_rake_projection = 0.975;
|
||||
|
||||
break;
|
||||
case SCULPT_TOOL_VCOL_BOUNDARY:
|
||||
case SCULPT_TOOL_PAINT:
|
||||
case SCULPT_TOOL_MASK:
|
||||
case SCULPT_TOOL_DRAW_FACE_SETS:
|
||||
@@ -2554,3 +2667,158 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
void BKE_brush_get_dyntopo(Brush *brush, Sculpt *sd, DynTopoSettings *out)
|
||||
{
|
||||
*out = brush->dyntopo;
|
||||
|
||||
// detect unconverted file data
|
||||
if (!out->inherit && !out->detail_range) {
|
||||
// reload default dyntopo settings
|
||||
Brush brush2 = *brush;
|
||||
|
||||
// don't copy heap allocd data
|
||||
brush2.curve = NULL;
|
||||
brush2.icon_imbuf = NULL;
|
||||
brush2.gpencil_settings = NULL;
|
||||
brush2.gradient = NULL;
|
||||
brush2.preview = NULL;
|
||||
|
||||
BKE_brush_sculpt_reset(&brush2);
|
||||
|
||||
brush->dyntopo = *out = brush2.dyntopo;
|
||||
|
||||
brush_free_data((ID *)&brush2);
|
||||
}
|
||||
else if (!out->detail_size) {
|
||||
brush->dyntopo.inherit |= DYNTOPO_INHERIT_DETAIL_SIZE;
|
||||
brush->dyntopo.detail_size = 8.0f;
|
||||
}
|
||||
|
||||
int inherit = out->inherit;
|
||||
|
||||
if (inherit & DYNTOPO_INHERIT_ALL) {
|
||||
inherit = 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
if (!(sd->flags & SCULPT_DYNTOPO_ENABLED)) {
|
||||
out->flag |= DYNTOPO_DISABLED;
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_INHERIT_MODE) {
|
||||
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
|
||||
out->mode = DYNTOPO_DETAIL_CONSTANT;
|
||||
}
|
||||
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
|
||||
out->mode = DYNTOPO_DETAIL_BRUSH;
|
||||
}
|
||||
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_MANUAL) {
|
||||
out->mode = DYNTOPO_DETAIL_MANUAL;
|
||||
}
|
||||
else {
|
||||
out->mode = DYNTOPO_DETAIL_RELATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_INHERIT_RADIUS_SCALE) {
|
||||
out->radius_scale = sd->dyntopo_radius_scale;
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_INHERIT_DETAIL_SIZE) {
|
||||
out->detail_size = sd->detail_size;
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_INHERIT_DETAIL_RANGE) {
|
||||
out->detail_range = sd->detail_range;
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_INHERIT_DETAIL_PERCENT) {
|
||||
out->detail_percent = sd->detail_percent;
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_INHERIT_SPACING) {
|
||||
out->spacing = sd->dyntopo_spacing;
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_INHERIT_CONSTANT_DETAIL) {
|
||||
out->constant_detail = sd->constant_detail;
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_SUBDIVIDE) {
|
||||
if (sd->flags & SCULPT_DYNTOPO_SUBDIVIDE) {
|
||||
out->flag |= DYNTOPO_SUBDIVIDE;
|
||||
}
|
||||
else {
|
||||
out->flag &= ~DYNTOPO_SUBDIVIDE;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_LOCAL_COLLAPSE) {
|
||||
if (sd->flags & SCULPT_DYNTOPO_LOCAL_COLLAPSE) {
|
||||
out->flag |= DYNTOPO_LOCAL_COLLAPSE;
|
||||
}
|
||||
else {
|
||||
out->flag &= ~DYNTOPO_LOCAL_COLLAPSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_LOCAL_SUBDIVIDE) {
|
||||
if (sd->flags & SCULPT_DYNTOPO_LOCAL_SUBDIVIDE) {
|
||||
out->flag |= DYNTOPO_LOCAL_SUBDIVIDE;
|
||||
}
|
||||
else {
|
||||
out->flag &= ~DYNTOPO_LOCAL_SUBDIVIDE;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_COLLAPSE) {
|
||||
if (sd->flags & SCULPT_DYNTOPO_COLLAPSE) {
|
||||
out->flag |= DYNTOPO_COLLAPSE;
|
||||
}
|
||||
else {
|
||||
out->flag &= ~DYNTOPO_COLLAPSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_CLEANUP) {
|
||||
if (sd->flags & SCULPT_DYNTOPO_CLEANUP) {
|
||||
out->flag |= DYNTOPO_CLEANUP;
|
||||
}
|
||||
else {
|
||||
out->flag &= ~DYNTOPO_CLEANUP;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool BKE_brush_hard_edge_mode_get(const Scene *scene, const Brush *brush)
|
||||
{
|
||||
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
||||
bool ret = (ups->flag & UNIFIED_PAINT_FLAG_HARD_EDGE_MODE) ? ups->hard_edge_mode :
|
||||
brush->flag2 & BRUSH_HARD_EDGE_MODE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BKE_brush_hard_edge_mode_set(Scene *scene, Brush *brush, bool val)
|
||||
{
|
||||
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
||||
|
||||
if (ups->flag & UNIFIED_PAINT_FLAG_HARD_EDGE_MODE) {
|
||||
ups->hard_edge_mode = val;
|
||||
}
|
||||
else {
|
||||
if (val) {
|
||||
brush->flag2 |= BRUSH_HARD_EDGE_MODE;
|
||||
}
|
||||
else {
|
||||
brush->flag2 &= ~BRUSH_HARD_EDGE_MODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float BKE_brush_fset_slide_get(const Scene *scene, const Brush *brush)
|
||||
{
|
||||
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
||||
|
||||
return BKE_brush_hard_edge_mode_get(scene, brush) ? 0.0f : brush->autosmooth_fset_slide;
|
||||
}
|
||||
|
683
source/blender/blenkernel/intern/brush_engine.c
Normal file
683
source/blender/blenkernel/intern/brush_engine.c
Normal file
@@ -0,0 +1,683 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_array.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_memarena.h"
|
||||
|
||||
#include "DNA_brush_enums.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_color_types.h"
|
||||
#include "DNA_curveprofile_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_sculpt_brush_types.h"
|
||||
|
||||
#include "BKE_brush.h"
|
||||
#include "BKE_colorband.h"
|
||||
#include "BKE_colortools.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_paint.h"
|
||||
|
||||
#include "BKE_brush_engine.h"
|
||||
#include "BKE_curveprofile.h"
|
||||
|
||||
#include "BLO_read_write.h"
|
||||
|
||||
#define ICON_NONE -1
|
||||
|
||||
/*
|
||||
Brush command lists.
|
||||
|
||||
Command lists are built dynamically from
|
||||
brush flags, pen input settings, etc.
|
||||
|
||||
Eventually they will be generated by node
|
||||
networks. BrushCommandPreset will be
|
||||
generated from the node group inputs.
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
BrushChannelType brush_builtin_channels[] = {
|
||||
{
|
||||
.name = "Radius",
|
||||
.idname = "RADIUS",
|
||||
.min = 0.001f,
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.max = 2048.0f,
|
||||
.soft_min = 0.1f,
|
||||
.soft_max = 1024.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Strength",
|
||||
.idname = "STRENGTH",
|
||||
.min = -1.0f,
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.max = 4.0f,
|
||||
.soft_min = 0.0f,
|
||||
.soft_max = 1.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = true},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Spacing",
|
||||
.idname = "SPACING",
|
||||
.min = 0.001f,
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.max = 4.0f,
|
||||
.soft_min = 0.005f,
|
||||
.soft_max = 2.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = true},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Autosmooth",
|
||||
.idname = "AUTOSMOOTH",
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.min = -1.0f,
|
||||
.max = 4.0f,
|
||||
.soft_min = 0.0f,
|
||||
.soft_max = 1.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false, .inv = true},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Topology Rake",
|
||||
.idname = "TOPOLOGY_RAKE",
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.min = -1.0f,
|
||||
.max = 4.0f,
|
||||
.soft_min = 0.0f,
|
||||
.soft_max = 1.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Autosmooth Radius Scale",
|
||||
.idname = "AUTOSMOOTH_RADIUS_SCALE",
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.min = 0.0001f,
|
||||
.max = 25.0f,
|
||||
.soft_min = 0.1f,
|
||||
.soft_max = 4.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Rake Radius Scale",
|
||||
.idname = "TOPOLOGY_RAKE_RADIUS_SCALE",
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.min = 0.0001f,
|
||||
.max = 25.0f,
|
||||
.soft_min = 0.1f,
|
||||
.soft_max = 4.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Face Set Slide",
|
||||
.idname = "FSET_SLIDE",
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.min = 0.0001f,
|
||||
.max = 1.0f,
|
||||
.soft_min = 0.1f,
|
||||
.soft_max = 1.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Boundary Smooth",
|
||||
.idname = "BOUNDARY_SMOOTH",
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.min = 0.0001f,
|
||||
.max = 1.0f,
|
||||
.soft_min = 0.1f,
|
||||
.soft_max = 1.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Projection",
|
||||
.idname = "PROJECTION",
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.min = 0.0001f,
|
||||
.max = 1.0f,
|
||||
.soft_min = 0.1f,
|
||||
.soft_max = 1.0f,
|
||||
.mappings = {
|
||||
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
|
||||
}
|
||||
},
|
||||
{
|
||||
.name = "Topology Rake Mode",
|
||||
.idname = "TOPOLOGY_RAKE_MODE",
|
||||
.type = BRUSH_CHANNEL_ENUM,
|
||||
.enumdef = {.items = {
|
||||
{0, "BRUSH_DIRECTION", ICON_NONE, "Stroke", "Stroke Direction"},
|
||||
{1, "CURVATURE", ICON_NONE, "Curvature", "Follow mesh curvature"},
|
||||
{-1, 0}
|
||||
}}
|
||||
},
|
||||
{
|
||||
.name = "Automasking",
|
||||
.idname = "AUTOMASKING",
|
||||
.flag = BRUSH_CHANNEL_INHERIT_IF_UNSET | BRUSH_CHANNEL_INHERIT,
|
||||
.type = BRUSH_CHANNEL_BITMASK,
|
||||
.enumdef = {.items = {
|
||||
{BRUSH_AUTOMASKING_BOUNDARY_EDGES, "BOUNDARY_EDGE", ICON_NONE, "Boundary Edges", ""},
|
||||
{BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS, "BOUNDARY_FACE_SETS", ICON_NONE, "Boundary Face Sets", ""},
|
||||
{BRUSH_AUTOMASKING_CONCAVITY, "CONCAVITY", ICON_NONE, "Concave", ""},
|
||||
{BRUSH_AUTOMASKING_INVERT_CONCAVITY, "INVERT_CONCAVITY", ICON_NONE, "Invert Concave", "Invert Concave Map"},
|
||||
{BRUSH_AUTOMASKING_FACE_SETS, "FACE_SETS", ICON_NONE, "Face Sets", ""},
|
||||
{BRUSH_AUTOMASKING_TOPOLOGY, "TOPOLOGY", ICON_NONE, "Topology", ""}
|
||||
}}
|
||||
},
|
||||
{
|
||||
.name = "Disable Dyntopo",
|
||||
.idname = "DYNTOPO_DISABLED",
|
||||
.type = BRUSH_CHANNEL_INT,
|
||||
.flag = BRUSH_CHANNEL_NO_MAPPINGS,
|
||||
.ivalue = 0
|
||||
},
|
||||
{
|
||||
.name = "Detail Range",
|
||||
.idname = "DYNTOPO_DETAIL_RANGE",
|
||||
.type = BRUSH_CHANNEL_FLOAT,
|
||||
.min = 0.001,
|
||||
.max = 0.99,
|
||||
.ivalue = 0
|
||||
},
|
||||
};
|
||||
|
||||
/* clang-format on */
|
||||
const int builtin_channel_len = ARRAY_SIZE(brush_builtin_channels);
|
||||
|
||||
void BKE_brush_channel_free(BrushChannel *ch)
|
||||
{
|
||||
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
|
||||
BKE_curvemapping_free_data(&ch->mappings[i].curve);
|
||||
}
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void BKE_brush_channel_copy(BrushChannel *dst, BrushChannel *src)
|
||||
{
|
||||
*dst = *src;
|
||||
|
||||
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
|
||||
BKE_curvemapping_copy_data(&dst->mappings[i].curve, &src->mappings[i].curve);
|
||||
}
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def)
|
||||
{
|
||||
memset(ch, 0, sizeof(*ch));
|
||||
|
||||
strcpy(ch->name, def->name);
|
||||
strcpy(ch->idname, def->idname);
|
||||
|
||||
ch->flag = def->flag;
|
||||
ch->fvalue = def->fvalue;
|
||||
ch->ivalue = def->ivalue;
|
||||
|
||||
ch->def = def;
|
||||
|
||||
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
|
||||
BrushMapping *map = ch->mappings + i;
|
||||
CurveMapping *curve = &map->curve;
|
||||
|
||||
memset(curve, 0, sizeof(*curve));
|
||||
|
||||
float min, max;
|
||||
|
||||
BrushMappingDef *mdef = (&def->mappings.pressure) + i;
|
||||
|
||||
if (mdef->min != mdef->max) {
|
||||
min = mdef->min;
|
||||
max = mdef->max;
|
||||
}
|
||||
else {
|
||||
min = 0.0f;
|
||||
max = 1.0f;
|
||||
}
|
||||
|
||||
if (mdef->inv) {
|
||||
ch->mappings[i].flag |= BRUSH_MAPPING_INVERT;
|
||||
}
|
||||
|
||||
int slope = CURVEMAP_SLOPE_POSITIVE;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BKE_curvemap_reset(&curve->cm[i],
|
||||
&(struct rctf){.xmax = 0, .ymax = min, .xmax = 1, .ymax = max},
|
||||
mdef->curve,
|
||||
slope);
|
||||
}
|
||||
|
||||
BKE_curvemapping_init(curve);
|
||||
|
||||
map->blendmode = mdef->blendmode;
|
||||
map->factor = 1.0f;
|
||||
|
||||
if (mdef->enabled) {
|
||||
map->flag |= BRUSH_MAPPING_ENABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BrushChannelSet *BKE_brush_channelset_create()
|
||||
{
|
||||
return (BrushChannelSet *)MEM_callocN(sizeof(BrushChannelSet), "BrushChannelSet");
|
||||
}
|
||||
|
||||
void BKE_brush_channelset_free(BrushChannelSet *chset)
|
||||
{
|
||||
if (chset->channels) {
|
||||
for (int i = 0; i < chset->totchannel; i++) {
|
||||
BKE_brush_channel_free(chset->channels + i);
|
||||
}
|
||||
|
||||
MEM_freeN(chset->channels);
|
||||
}
|
||||
MEM_freeN(chset);
|
||||
}
|
||||
|
||||
void BKE_brush_channelset_add(BrushChannelSet *chset, BrushChannel *ch)
|
||||
{
|
||||
chset->totchannel++;
|
||||
|
||||
if (!chset->channels) {
|
||||
chset->channels = MEM_callocN(sizeof(BrushChannel) * chset->totchannel, "chset->channels");
|
||||
}
|
||||
else {
|
||||
chset->channels = MEM_recallocN(chset->channels, sizeof(BrushChannel) * chset->totchannel);
|
||||
}
|
||||
|
||||
memcpy(chset->channels + chset->totchannel - 1, ch, sizeof(BrushChannel));
|
||||
}
|
||||
|
||||
ATTR_NO_OPT BrushChannel *BKE_brush_channelset_lookup(BrushChannelSet *chset, const char *idname)
|
||||
{
|
||||
for (int i = 0; i < chset->totchannel; i++) {
|
||||
if (STREQ(chset->channels[i].idname, idname)) {
|
||||
return chset->channels + i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool BKE_brush_channelset_has(BrushChannelSet *chset, const char *idname)
|
||||
{
|
||||
return BKE_brush_channelset_lookup(chset, idname) != NULL;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT void BKE_brush_channelset_add_builtin(BrushChannelSet *chset, const char *idname)
|
||||
{
|
||||
BrushChannelType *def = NULL;
|
||||
|
||||
for (int i = 0; i < builtin_channel_len; i++) {
|
||||
BrushChannelType *def2 = brush_builtin_channels + i;
|
||||
|
||||
if (STREQ(def2->idname, idname)) {
|
||||
def = def2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!def) {
|
||||
printf("%s: Could not find brush %s\n", __func__, idname);
|
||||
return;
|
||||
}
|
||||
|
||||
BrushChannel ch;
|
||||
|
||||
BKE_brush_channel_init(&ch, def);
|
||||
BKE_brush_channelset_add(chset, &ch);
|
||||
}
|
||||
|
||||
bool BKE_brush_channelset_ensure_builtin(BrushChannelSet *chset, const char *idname)
|
||||
{
|
||||
if (!BKE_brush_channelset_has(chset, idname)) {
|
||||
BKE_brush_channelset_add_builtin(chset, idname);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define ADDCH(name) BKE_brush_channelset_ensure_builtin(chset, name)
|
||||
#define GETCH(name) BKE_brush_channelset_lookup(chset, name)
|
||||
|
||||
void BKE_brush_channelset_merge(BrushChannelSet *dst,
|
||||
BrushChannelSet *child,
|
||||
BrushChannelSet *parent)
|
||||
{
|
||||
// first add missing channels
|
||||
|
||||
for (int step = 0; step < 2; step++) {
|
||||
BrushChannelSet *chset = step ? parent : child;
|
||||
|
||||
for (int i = 0; i < chset->totchannel; i++) {
|
||||
BrushChannel *ch = chset->channels + i;
|
||||
|
||||
if (BKE_brush_channelset_has(dst, ch->idname)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BrushChannel ch2;
|
||||
BKE_brush_channel_copy(&ch2, ch);
|
||||
BKE_brush_channelset_add(chset, &ch2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < child->totchannel; i++) {
|
||||
BrushChannel *ch = child->channels + i;
|
||||
BrushChannel *mch = BKE_brush_channelset_lookup(dst, ch->idname);
|
||||
BrushChannel *pch = BKE_brush_channelset_lookup(parent, ch->name);
|
||||
|
||||
bool ok = ch->flag & BRUSH_CHANNEL_INHERIT;
|
||||
|
||||
if (ch->flag & BRUSH_CHANNEL_INHERIT) {
|
||||
BKE_brush_channel_free(mch);
|
||||
BKE_brush_channel_copy(mch, pch);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch->type == BRUSH_CHANNEL_BITMASK && (ch->flag & BRUSH_CHANNEL_INHERIT_IF_UNSET)) {
|
||||
mch->ivalue = ch->ivalue | pch->ivalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_brush_resolve_channels(Brush *brush, Sculpt *sd)
|
||||
{
|
||||
if (brush->channels_final) {
|
||||
BKE_brush_channelset_free(brush->channels_final);
|
||||
}
|
||||
|
||||
brush->channels_final = BKE_brush_channelset_create();
|
||||
|
||||
BKE_brush_channelset_merge(brush->channels_final, brush->channels, sd->channels);
|
||||
|
||||
if (!brush->commandlist) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrushCommandList *cl = brush->commandlist;
|
||||
|
||||
for (int i = 0; i < cl->totcommand; i++) {
|
||||
BrushCommand *command = cl->commands + i;
|
||||
|
||||
if (command->params_final) {
|
||||
BKE_brush_channelset_free(command->params_final);
|
||||
}
|
||||
|
||||
command->params_final = BKE_brush_channelset_create();
|
||||
BKE_brush_channelset_merge(command->params_final, command->params, brush->channels_final);
|
||||
}
|
||||
}
|
||||
|
||||
int BKE_brush_channel_get_int(BrushChannelSet *chset, char *idname)
|
||||
{
|
||||
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
|
||||
|
||||
if (!ch) {
|
||||
printf("%s, unknown channel %s", __func__, idname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ch->ivalue;
|
||||
}
|
||||
|
||||
float BKE_brush_channel_get_float(BrushChannelSet *chset, char *idname)
|
||||
{
|
||||
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
|
||||
|
||||
if (!ch) {
|
||||
printf("%s, unknown channel %s", __func__, idname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ch->fvalue;
|
||||
}
|
||||
|
||||
float BKE_brush_channel_set_float(BrushChannelSet *chset, char *idname, float val)
|
||||
{
|
||||
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
|
||||
|
||||
if (!ch) {
|
||||
printf("%s, unknown channel %s", __func__, idname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float old = ch->fvalue;
|
||||
|
||||
ch->fvalue = val;
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
void BKE_brush_init_toolsettings(Sculpt *sd)
|
||||
{
|
||||
BrushChannelSet *chset = sd->channels = BKE_brush_channelset_create();
|
||||
|
||||
ADDCH("RADIUS");
|
||||
ADDCH("STRENGTH");
|
||||
ADDCH("AUTOMASKING");
|
||||
ADDCH("DYNTOPO_DISABLED");
|
||||
ADDCH("DYNTOPO_DETAIL_RANGE");
|
||||
}
|
||||
|
||||
void BKE_brush_builtin_create(Brush *brush, int tool)
|
||||
{
|
||||
if (brush->channels) {
|
||||
BKE_brush_channelset_free(brush->channels);
|
||||
}
|
||||
|
||||
BrushChannelSet *chset = brush->channels = BKE_brush_channelset_create();
|
||||
|
||||
ADDCH("RADIUS");
|
||||
ADDCH("STRENGTH");
|
||||
ADDCH("AUTOSMOOTH");
|
||||
ADDCH("TOPOLOGY_RAKE");
|
||||
ADDCH("AUTOSMOOTH_RADIUS_SCALE");
|
||||
ADDCH("TOPOLOGY_RAKE_RADIUS_SCALE");
|
||||
|
||||
ADDCH("AUTOMASKING");
|
||||
|
||||
switch (tool) {
|
||||
case SCULPT_TOOL_DRAW: {
|
||||
BrushChannel *ch = GETCH("STRENGTH");
|
||||
|
||||
ch->mappings[BRUSH_MAPPING_PRESSURE].flag &= ~BRUSH_MAPPING_ENABLED;
|
||||
ch->flag = BRUSH_CHANNEL_INHERIT;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// implement me!
|
||||
BKE_brush_channelset_free(chset);
|
||||
brush->channels = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BrushCommandList *BKE_brush_commandlist_create()
|
||||
{
|
||||
return MEM_callocN(sizeof(BrushCommandList), "BrushCommandList");
|
||||
}
|
||||
void BKE_brush_commandlist_free(BrushCommandList *cl)
|
||||
{
|
||||
for (int i = 0; i < cl->totcommand; i++) {
|
||||
BrushCommand *cmd = cl->commands + i;
|
||||
|
||||
if (cmd->params) {
|
||||
BKE_brush_channelset_free(cmd->params);
|
||||
}
|
||||
|
||||
if (cmd->params_final) {
|
||||
BKE_brush_channelset_free(cmd->params_final);
|
||||
}
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(cl->commands);
|
||||
|
||||
MEM_freeN(cl);
|
||||
}
|
||||
BrushCommand *BKE_brush_commandlist_add(BrushCommandList *cl)
|
||||
{
|
||||
cl->totcommand++;
|
||||
|
||||
if (!cl->commands) {
|
||||
cl->commands = MEM_callocN(sizeof(BrushCommand) * cl->totcommand, "BrushCommand");
|
||||
}
|
||||
else {
|
||||
cl->commands = MEM_recallocN(cl->commands, sizeof(BrushCommand) * cl->totcommand);
|
||||
}
|
||||
|
||||
BrushCommand *cmd = cl->commands + cl->totcommand - 1;
|
||||
cmd->params = BKE_brush_channelset_create();
|
||||
cmd->params_final = NULL;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
BrushCommand *BKE_brush_command_init(BrushCommand *command, int tool)
|
||||
{
|
||||
BrushChannelSet *chset = command->params;
|
||||
|
||||
ADDCH("SPACING");
|
||||
|
||||
switch (tool) {
|
||||
case SCULPT_TOOL_DRAW:
|
||||
ADDCH("RADIUS");
|
||||
ADDCH("STRENGTH");
|
||||
break;
|
||||
case SCULPT_TOOL_SMOOTH:
|
||||
ADDCH("RADIUS");
|
||||
ADDCH("STRENGTH");
|
||||
ADDCH("FSET_SLIDE");
|
||||
ADDCH("BOUNDARY_SMOOTH");
|
||||
ADDCH("PROJECTION");
|
||||
break;
|
||||
case SCULPT_TOOL_TOPOLOGY_RAKE:
|
||||
ADDCH("RADIUS");
|
||||
ADDCH("STRENGTH");
|
||||
// ADDCH("FSET_SLIDE");
|
||||
// ADDCH("BOUNDARY_SMOOTH");
|
||||
ADDCH("PROJECTION");
|
||||
ADDCH("TOPOLOGY_RAKE_MODE");
|
||||
break;
|
||||
case SCULPT_TOOL_DYNTOPO:
|
||||
break;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
void BKE_builtin_commandlist_create(BrushChannelSet *chset, BrushCommandList *cl, int tool)
|
||||
{
|
||||
BrushCommand *cmd;
|
||||
|
||||
cmd = BKE_brush_commandlist_add(cl);
|
||||
BKE_brush_command_init(cmd, tool);
|
||||
|
||||
for (int i = 0; i < cmd->totparam; i++) {
|
||||
// inherit from brush channels for main tool
|
||||
cmd->params->channels[i].flag |= BRUSH_CHANNEL_INHERIT;
|
||||
}
|
||||
|
||||
float radius = BKE_brush_channel_get_float(chset, "RADIUS");
|
||||
float autosmooth_scale = BKE_brush_channel_get_float(chset, "AUTOSMOOTH_RADIUS_SCALE");
|
||||
|
||||
float autosmooth = BKE_brush_channel_get_float(chset, "AUTOSMOOTH");
|
||||
if (autosmooth > 0.0f) {
|
||||
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl), SCULPT_TOOL_SMOOTH);
|
||||
BKE_brush_channel_set_float(cmd->params, "STRENGTH", autosmooth);
|
||||
BKE_brush_channel_set_float(cmd->params, "RADIUS", radius * autosmooth_scale);
|
||||
BKE_brush_channel_set_float(
|
||||
cmd->params, "PROJECTION", BKE_brush_channel_get_float(chset, "AUTOSMOOTH_PROJECTION"));
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_brush_channelset_read(BlendDataReader *reader, BrushChannelSet *cset)
|
||||
{
|
||||
BLO_read_data_address(reader, &cset->channels);
|
||||
|
||||
for (int i = 0; i < cset->totchannel; i++) {
|
||||
BrushChannel *ch = cset->channels + i;
|
||||
|
||||
for (int j = 0; j < BRUSH_MAPPING_MAX; j++) {
|
||||
BKE_curvemapping_blend_read(reader, &ch->mappings[j].curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_brush_channelset_write(BlendWriter *writer, BrushChannelSet *cset)
|
||||
{
|
||||
BLO_write_struct(writer, BrushChannelSet, cset);
|
||||
BLO_write_struct_array_by_name(writer, "BrushChannel", cset->totchannel, cset->channels);
|
||||
|
||||
for (int i = 0; i < cset->totchannel; i++) {
|
||||
BrushChannel *ch = cset->channels + i;
|
||||
|
||||
for (int j = 0; j < BRUSH_MAPPING_MAX; j++) {
|
||||
BKE_curvemapping_blend_write(writer, &ch->mappings[j].curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/* idea for building built-in preset node graphs:
|
||||
from brush_builder import Builder;
|
||||
|
||||
def build(input, output):
|
||||
input.add("Strength", "float", "strength").range(0.0, 3.0)
|
||||
input.add("Radius", "float", "radius").range(0.01, 1024.0)
|
||||
input.add("Autosmooth", "float", "autosmooth").range(0.0, 4.0)
|
||||
input.add("Topology Rake", "float", "topology rake").range(0.0, 4.0)
|
||||
input.add("Smooth Radius Scale", "float", "autosmooth_radius_scale").range(0.01, 5.0)
|
||||
input.add("Rake Radius Scale", "float", "toporake_radius_scale").range(0.01, 5.0)
|
||||
|
||||
draw = input.make.tool("DRAW")
|
||||
draw.radius = input.radius
|
||||
draw.strength = input.strength
|
||||
|
||||
smooth = input.make.tool("SMOOTH")
|
||||
smooth.radius = input.radius * input.autosmooth_radius_scale
|
||||
smooth.strength = input.autosmooth;
|
||||
smooth.flow = draw.outflow
|
||||
|
||||
rake = input.make.tool("TOPORAKE")
|
||||
rake.radius = input.radius * input.toporake_radius_scale
|
||||
rake.strength = input.topology;
|
||||
rake.flow = smooth.outflow
|
||||
|
||||
output.out = rake.outflow
|
||||
|
||||
preset = Builder(build)
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
bNodeType sculpt_tool_node = {
|
||||
.idname = "SculptTool",
|
||||
.ui_name = "SculptTool",
|
||||
};*/
|
||||
/* cland-format on */
|
@@ -171,8 +171,16 @@ static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
|
||||
if (!cddm->pmap && ob->type == OB_MESH) {
|
||||
Mesh *me = ob->data;
|
||||
|
||||
BKE_mesh_vert_poly_map_create(
|
||||
&cddm->pmap, &cddm->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
|
||||
BKE_mesh_vert_poly_map_create(&cddm->pmap,
|
||||
&cddm->pmap_mem,
|
||||
me->mvert,
|
||||
me->medge,
|
||||
me->mpoly,
|
||||
me->mloop,
|
||||
me->totvert,
|
||||
me->totpoly,
|
||||
me->totloop,
|
||||
false);
|
||||
}
|
||||
|
||||
return cddm->pmap;
|
||||
|
@@ -688,9 +688,12 @@ static Collection *collection_duplicate_recursive(Main *bmain,
|
||||
Collection *BKE_collection_duplicate(Main *bmain,
|
||||
Collection *parent,
|
||||
Collection *collection,
|
||||
eDupli_ID_Flags duplicate_flags,
|
||||
eLibIDDuplicateFlags duplicate_options)
|
||||
const uint duplicate_flags_in, // it's not const!! - joeedh
|
||||
const uint duplicate_options_in) // not const!
|
||||
{
|
||||
uint duplicate_flags = duplicate_flags_in;
|
||||
uint duplicate_options = duplicate_options_in;
|
||||
|
||||
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
|
||||
const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0;
|
||||
|
||||
|
@@ -100,7 +100,7 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
|
||||
* for #Curve.bevresol is 32. */
|
||||
float *quarter_coords_x = alloca(sizeof(float) * (cu->bevresol + 1));
|
||||
float *quarter_coords_y = alloca(sizeof(float) * (cu->bevresol + 1));
|
||||
bevel_quarter_fill(cu, quarter_coords_x, quarter_coords_y);
|
||||
bevel_quarter_fill((Curve *)cu, quarter_coords_x, quarter_coords_y);
|
||||
|
||||
int nr;
|
||||
if (fill_type == FULL) {
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_endian_switch.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_color_blend.h"
|
||||
@@ -73,6 +74,32 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "siz
|
||||
|
||||
static CLG_LogRef LOG = {"bke.customdata"};
|
||||
|
||||
bool CustomData_layout_is_same(const CustomData *_a, const CustomData *_b)
|
||||
{
|
||||
CustomData a = *_a;
|
||||
CustomData b = *_b;
|
||||
|
||||
a.layers = b.layers = NULL;
|
||||
a.pool = b.pool = NULL;
|
||||
|
||||
if (memcmp((void *)&a, (void *)&b, sizeof(CustomData)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < a.totlayer; i++) {
|
||||
CustomDataLayer cla = _a->layers[i];
|
||||
CustomDataLayer clb = _b->layers[i];
|
||||
|
||||
cla.data = clb.data = NULL;
|
||||
|
||||
if (memcmp((void *)&cla, (void *)&clb, sizeof(CustomDataLayer)) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Update mask_dst with layers defined in mask_src (equivalent to a bitwise OR). */
|
||||
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
|
||||
const CustomData_MeshMasks *mask_src)
|
||||
@@ -1475,6 +1502,93 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool
|
||||
return has_errors;
|
||||
}
|
||||
|
||||
static void layerDynTopoVert_copy(const void *source, void *dest, int count)
|
||||
{
|
||||
const MDynTopoVert *mv = (MDynTopoVert *)dest;
|
||||
|
||||
memcpy(dest, source, count * sizeof(MDynTopoVert));
|
||||
}
|
||||
|
||||
static void layerDynTopoVert_interp(
|
||||
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
|
||||
{
|
||||
float co[3], no[3], origmask, color[4];
|
||||
MDynTopoVert *mv = (MDynTopoVert *)dest;
|
||||
float totweight = 0.0f;
|
||||
|
||||
if (count == 0) {
|
||||
memset(mv, 0, sizeof(*mv));
|
||||
return;
|
||||
}
|
||||
|
||||
zero_v3(co);
|
||||
zero_v3(no);
|
||||
origmask = 0.0f;
|
||||
zero_v4(color);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
MDynTopoVert *mv2 = (MDynTopoVert *)sources[i];
|
||||
float w;
|
||||
|
||||
if (i == 0) { // copy flag from first source
|
||||
mv->flag = mv2->flag;
|
||||
mv->stroke_id = mv2->stroke_id;
|
||||
}
|
||||
|
||||
if (sub_weights) {
|
||||
w = sub_weights[i];
|
||||
}
|
||||
else {
|
||||
w = 1.0f;
|
||||
}
|
||||
|
||||
madd_v3_v3fl(co, mv2->origco, w);
|
||||
madd_v3_v3fl(no, mv2->origno, w);
|
||||
madd_v4_v4fl(color, mv2->origcolor, w);
|
||||
origmask += mv2->origmask * w;
|
||||
|
||||
totweight += w;
|
||||
}
|
||||
|
||||
float mul = 1.0f / totweight;
|
||||
|
||||
mul_v3_fl(co, mul);
|
||||
normalize_v3(no);
|
||||
|
||||
mul_v4_fl(color, mul);
|
||||
origmask *= mul;
|
||||
|
||||
copy_v3_v3(mv->origco, co);
|
||||
copy_v3_v3(mv->origno, no);
|
||||
copy_v4_v4(mv->origcolor, color);
|
||||
|
||||
mv->origmask = origmask;
|
||||
}
|
||||
|
||||
static void layerCopy_noop(const void *UNUSED(source), void *UNUSED(dest), int UNUSED(count))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
static void layerInterp_noop(const void **UNUSED(sources),
|
||||
const float *UNUSED(weights),
|
||||
const float *UNUSED(sub_weights),
|
||||
int UNUSED(count),
|
||||
void *UNUSED(dest))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
static void layerDefault_mesh_id(void *data, int count)
|
||||
{
|
||||
int *val = (int *)data;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
// val[i] = -1;
|
||||
val[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||
/* 0: CD_MVERT */
|
||||
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
@@ -1856,7 +1970,24 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
};
|
||||
/* 51 CD_DYNTOPO_VERT */
|
||||
{sizeof(MDynTopoVert),
|
||||
"MDynTopoVert",
|
||||
1,
|
||||
NULL, // flag singleton layer
|
||||
layerDynTopoVert_copy,
|
||||
NULL,
|
||||
layerDynTopoVert_interp},
|
||||
/*52 CD_MESH_ID */
|
||||
{sizeof(unsigned int),
|
||||
"MIntProperty",
|
||||
1,
|
||||
NULL, // flag singleton layer
|
||||
layerCopy_propInt,
|
||||
NULL,
|
||||
layerInterp_noop,
|
||||
NULL,
|
||||
layerDefault_mesh_id}};
|
||||
|
||||
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
|
||||
/* 0-4 */ "CDMVert",
|
||||
@@ -1912,62 +2043,65 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
|
||||
"CDPropFloat3",
|
||||
"CDPropFloat2",
|
||||
"CDPropBoolean",
|
||||
};
|
||||
"CDDyntopoVert"};
|
||||
|
||||
const CustomData_MeshMasks CD_MASK_BAREMESH = {
|
||||
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT,
|
||||
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT,
|
||||
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_MESH_ID,
|
||||
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_MESH_ID,
|
||||
.fmask = 0,
|
||||
.lmask = CD_MASK_MLOOP,
|
||||
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP,
|
||||
.lmask = CD_MASK_MLOOP | CD_MASK_MESH_ID,
|
||||
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_MESH_ID,
|
||||
};
|
||||
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
|
||||
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
|
||||
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
|
||||
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX | CD_MASK_MESH_ID,
|
||||
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX | CD_MASK_MESH_ID,
|
||||
.fmask = 0,
|
||||
.lmask = CD_MASK_MLOOP,
|
||||
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
|
||||
.lmask = CD_MASK_MLOOP | CD_MASK_MESH_ID,
|
||||
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX | CD_MASK_MESH_ID,
|
||||
};
|
||||
const CustomData_MeshMasks CD_MASK_MESH = {
|
||||
.vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
|
||||
CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
|
||||
.emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
|
||||
CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_MESH_ID),
|
||||
.emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
|
||||
.fmask = 0,
|
||||
.lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
|
||||
CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
|
||||
CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL |
|
||||
CD_MASK_MESH_ID),
|
||||
.pmask = (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
|
||||
CD_MASK_SCULPT_FACE_SETS),
|
||||
CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID),
|
||||
};
|
||||
const CustomData_MeshMasks CD_MASK_EDITMESH = {
|
||||
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
|
||||
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
|
||||
.emask = (CD_MASK_PROP_ALL),
|
||||
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_MESH_ID),
|
||||
.emask = (CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
|
||||
.fmask = 0,
|
||||
.lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
|
||||
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
|
||||
.pmask = (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
|
||||
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
|
||||
.pmask = (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID),
|
||||
};
|
||||
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
|
||||
.vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
|
||||
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
|
||||
CD_MASK_PROP_COLOR),
|
||||
.emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
|
||||
CD_MASK_PROP_COLOR | CD_MASK_MESH_ID),
|
||||
.emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
|
||||
.fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
|
||||
.lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
|
||||
CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
|
||||
CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
|
||||
CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL |
|
||||
CD_MASK_MESH_ID), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
|
||||
.pmask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
|
||||
CD_MASK_SCULPT_FACE_SETS),
|
||||
CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID),
|
||||
};
|
||||
const CustomData_MeshMasks CD_MASK_BMESH = {
|
||||
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
|
||||
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
|
||||
.emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
|
||||
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR |
|
||||
CD_MASK_DYNTOPO_VERT | CD_MASK_MESH_ID),
|
||||
.emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL |
|
||||
CD_MASK_MESH_ID),
|
||||
.fmask = 0,
|
||||
.lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
|
||||
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
|
||||
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
|
||||
.pmask = (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
|
||||
CD_MASK_SCULPT_FACE_SETS),
|
||||
CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID),
|
||||
};
|
||||
/**
|
||||
* cover values copied by #mesh_loops_to_tessdata
|
||||
@@ -2009,6 +2143,11 @@ static const LayerTypeInfo *layerType_getInfo(int type)
|
||||
return &LAYERTYPEINFO[type];
|
||||
}
|
||||
|
||||
int CustomData_get_elem_size(CustomDataLayer *layer)
|
||||
{
|
||||
return layerType_getInfo(layer->type)->size;
|
||||
}
|
||||
|
||||
static const char *layerType_getName(int type)
|
||||
{
|
||||
if (type < 0 || type >= CD_NUMTYPES) {
|
||||
@@ -2093,6 +2232,26 @@ static bool customdata_typemap_is_valid(const CustomData *data)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* copies all customdata layers without allocating data,
|
||||
* and without respect to type masks or NO_COPY/etc flags*/
|
||||
void CustomData_copy_all_layout(const struct CustomData *source, struct CustomData *dest)
|
||||
{
|
||||
*dest = *source;
|
||||
|
||||
if (dest->pool) {
|
||||
dest->pool = NULL;
|
||||
}
|
||||
|
||||
if (source->layers) {
|
||||
dest->layers = MEM_mallocN(sizeof(*dest->layers) * source->totlayer, __func__);
|
||||
|
||||
for (int i = 0; i < source->totlayer; i++) {
|
||||
dest->layers[i] = source->layers[i];
|
||||
dest->layers[i].data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomData_merge(const struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
CustomDataMask mask,
|
||||
@@ -2883,6 +3042,24 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type)
|
||||
return (layer->flag & CD_FLAG_NOFREE) != 0;
|
||||
}
|
||||
|
||||
void CustomData_unmark_temporary_nocopy(CustomData *data)
|
||||
{
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
if (data->layers[i].flag & CD_FLAG_TEMPORARY) {
|
||||
data->layers[i].flag &= ~CD_FLAG_NOCOPY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_mark_temporary_nocopy(CustomData *data)
|
||||
{
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
if (data->layers[i].flag & CD_FLAG_TEMPORARY) {
|
||||
data->layers[i].flag |= CD_FLAG_NOCOPY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_free_temporary(CustomData *data, int totelem)
|
||||
{
|
||||
int i, j;
|
||||
@@ -3739,6 +3916,12 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n
|
||||
int offset = data->layers[n].offset;
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
|
||||
|
||||
/* can't allow this to be called on CD_MESH_ID */
|
||||
|
||||
if (data->layers[n].type == CD_MESH_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeInfo->set_default) {
|
||||
typeInfo->set_default(POINTER_OFFSET(*block, offset), 1);
|
||||
}
|
||||
@@ -3758,6 +3941,95 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2)
|
||||
{
|
||||
int cd_id = data->typemap[CD_MESH_ID];
|
||||
cd_id = cd_id >= 0 ? data->layers[cd_id].offset : -1;
|
||||
|
||||
void *tmp = *block1;
|
||||
*block1 = *block2;
|
||||
*block2 = tmp;
|
||||
|
||||
// unswap ids if they exist
|
||||
if (cd_id != -1 && *block1 && *block2) {
|
||||
int *id1 = (int *)(((char *)*block1) + cd_id);
|
||||
int *id2 = (int *)(((char *)*block2) + cd_id);
|
||||
|
||||
tmp = *id1;
|
||||
*id1 = *id2;
|
||||
*id2 = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_bmesh_swap_data(CustomData *source,
|
||||
CustomData *dest,
|
||||
void *src_block,
|
||||
void **dest_block)
|
||||
{
|
||||
int src_i = 0;
|
||||
int dest_i = 0;
|
||||
int dest_i_start = 0;
|
||||
|
||||
if (*dest_block == NULL) {
|
||||
CustomData_bmesh_alloc_block(dest, dest_block);
|
||||
|
||||
if (*dest_block) {
|
||||
memset(*dest_block, 0, dest->totsize);
|
||||
CustomData_bmesh_set_default(dest, dest_block);
|
||||
}
|
||||
}
|
||||
|
||||
for (src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
/* find the first dest layer with type >= the source type
|
||||
* (this should work because layers are ordered by type)
|
||||
*/
|
||||
while (dest_i_start < dest->totlayer &&
|
||||
dest->layers[dest_i_start].type < source->layers[src_i].type) {
|
||||
dest_i_start++;
|
||||
}
|
||||
|
||||
if (source->layers[src_i].type == CD_MESH_ID) {
|
||||
// do not swap ids
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if there are no more dest layers, we're done */
|
||||
if (dest_i_start >= dest->totlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
dest_i = dest_i_start;
|
||||
|
||||
while (dest_i < dest->totlayer && dest->layers[dest_i].type == source->layers[src_i].type) {
|
||||
/* if we found a matching layer, copy the data */
|
||||
if (dest->layers[dest_i].type == source->layers[src_i].type &&
|
||||
STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
|
||||
void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
|
||||
void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
|
||||
const uint size = typeInfo->size;
|
||||
|
||||
// swap data
|
||||
char *bsrc = (char *)src_data;
|
||||
char *bdst = (char *)dest_data;
|
||||
|
||||
for (int j = 0; j < size; j++) {
|
||||
char t = *bsrc;
|
||||
*bsrc = *bdst;
|
||||
*bdst = t;
|
||||
|
||||
bsrc++;
|
||||
bdst++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
|
||||
CustomData *dest,
|
||||
void *src_block,
|
||||
@@ -3775,50 +4047,59 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
|
||||
}
|
||||
}
|
||||
|
||||
for (int dest_i = 0; dest_i < dest->totlayer; dest_i++) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
dest_i++;
|
||||
}
|
||||
|
||||
/* copies a layer at a time */
|
||||
int dest_i = 0;
|
||||
int dest_i_start = 0;
|
||||
|
||||
for (int src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
|
||||
/* find the first dest layer with type >= the source type
|
||||
* (this should work because layers are ordered by type)
|
||||
*/
|
||||
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
dest_i++;
|
||||
while (dest_i_start < dest->totlayer &&
|
||||
dest->layers[dest_i_start].type < source->layers[src_i].type) {
|
||||
dest_i_start++;
|
||||
}
|
||||
|
||||
/* if there are no more dest layers, we're done */
|
||||
if (dest_i >= dest->totlayer) {
|
||||
if (dest_i_start >= dest->totlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we found a matching layer, copy the data */
|
||||
if (dest->layers[dest_i].type == source->layers[src_i].type &&
|
||||
STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
|
||||
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
|
||||
const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
|
||||
void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(src_data, dest_data, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dest_data, src_data, typeInfo->size);
|
||||
int dest_i = dest_i_start;
|
||||
|
||||
/*Previously this code was only checking one source layer against one destination.
|
||||
Now it scans all the layers of that type. - joeedh
|
||||
*/
|
||||
while (dest_i < dest->totlayer && dest->layers[dest_i].type == source->layers[src_i].type) {
|
||||
/* if we found a matching layer, copy the data */
|
||||
if (STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
|
||||
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
|
||||
if (dest->layers[dest_i].flag & CD_FLAG_ELEM_NOCOPY) {
|
||||
break;
|
||||
}
|
||||
|
||||
const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
|
||||
void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(src_data, dest_data, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dest_data, src_data, typeInfo->size);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* if there are multiple source & dest layers of the same type,
|
||||
* we don't want to copy all source layers to the same dest, so
|
||||
* increment dest_i
|
||||
*/
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
|
||||
while (dest_i < dest->totlayer) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_bmesh_copy_data(const CustomData *source,
|
||||
|
@@ -150,6 +150,7 @@ bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
|
||||
case DT_TYPE_UV:
|
||||
ret = true;
|
||||
break;
|
||||
case DT_TYPE_PROPCOL:
|
||||
case DT_TYPE_VCOL:
|
||||
*r_advanced_mixing = true;
|
||||
*r_threshold = true;
|
||||
@@ -230,12 +231,12 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
|
||||
return CD_FAKE_SHARP;
|
||||
case DT_TYPE_FREESTYLE_FACE:
|
||||
return CD_FREESTYLE_FACE;
|
||||
|
||||
case DT_TYPE_VCOL:
|
||||
return CD_MLOOPCOL;
|
||||
case DT_TYPE_LNOR:
|
||||
return CD_FAKE_LNOR;
|
||||
|
||||
case DT_TYPE_PROPCOL:
|
||||
return CD_PROP_COLOR;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
}
|
||||
@@ -253,6 +254,8 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
|
||||
return DT_MULTILAYER_INDEX_UV;
|
||||
case DT_TYPE_VCOL:
|
||||
return DT_MULTILAYER_INDEX_VCOL;
|
||||
case DT_TYPE_PROPCOL:
|
||||
return DT_MULTILAYER_INDEX_PROPCOL;
|
||||
default:
|
||||
return DT_MULTILAYER_INDEX_INVALID;
|
||||
}
|
||||
|
6175
source/blender/blenkernel/intern/dyntopo.c
Normal file
6175
source/blender/blenkernel/intern/dyntopo.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -184,7 +184,7 @@ static void idp_repr_fn_recursive(struct ReprState *state, const IDProperty *pro
|
||||
const ID *id = prop->data.pointer;
|
||||
if (id != NULL) {
|
||||
STR_APPEND_STR("bpy.data.");
|
||||
STR_APPEND_STR(BKE_idtype_idcode_to_name_plural(GS(id->name)));
|
||||
STR_APPEND_STR(BKE_idtype_idcode_to_name_plural((short)GS(id->name)));
|
||||
STR_APPEND_STR("[");
|
||||
STR_APPEND_STR_QUOTE(id->name + 2);
|
||||
STR_APPEND_STR("]");
|
||||
|
@@ -674,7 +674,7 @@ ID *BKE_id_copy(Main *bmain, const ID *id)
|
||||
* Invokes the appropriate copy method for the block and returns the result in
|
||||
* newid, unless test. Returns true if the block can be copied.
|
||||
*/
|
||||
ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplicate_flags)
|
||||
ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const uint duplicate_flags)
|
||||
{
|
||||
if (id == NULL) {
|
||||
return id;
|
||||
|
@@ -1123,14 +1123,15 @@ Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference)
|
||||
return result;
|
||||
}
|
||||
|
||||
BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me,
|
||||
BMesh *BKE_mesh_to_bmesh_ex(const Object *ob,
|
||||
const Mesh *me,
|
||||
const struct BMeshCreateParams *create_params,
|
||||
const struct BMeshFromMeshParams *convert_params)
|
||||
{
|
||||
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
|
||||
|
||||
BMesh *bm = BM_mesh_create(&allocsize, create_params);
|
||||
BM_mesh_bm_from_me(bm, me, convert_params);
|
||||
BM_mesh_bm_from_me((Object *)ob, bm, me, convert_params);
|
||||
|
||||
return bm;
|
||||
}
|
||||
@@ -1140,7 +1141,8 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
|
||||
const bool add_key_index,
|
||||
const struct BMeshCreateParams *params)
|
||||
{
|
||||
return BKE_mesh_to_bmesh_ex(me,
|
||||
return BKE_mesh_to_bmesh_ex(ob,
|
||||
me,
|
||||
params,
|
||||
&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = false,
|
||||
@@ -1156,8 +1158,13 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
|
||||
{
|
||||
BLI_assert(params->calc_object_remap == false);
|
||||
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
|
||||
BM_mesh_bm_to_me(NULL, bm, mesh, params);
|
||||
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
|
||||
|
||||
BM_mesh_bm_to_me(NULL, NULL, bm, mesh, params);
|
||||
|
||||
if (me_settings) {
|
||||
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
@@ -213,11 +213,14 @@ class MeshFairingContext : public FairingContext {
|
||||
mloop_ = mesh->mloop;
|
||||
BKE_mesh_vert_loop_map_create(&vlmap_,
|
||||
&vlmap_mem_,
|
||||
mesh->mvert,
|
||||
mesh->medge,
|
||||
mesh->mpoly,
|
||||
mesh->mloop,
|
||||
mesh->totvert,
|
||||
mesh->totpoly,
|
||||
mesh->totloop);
|
||||
mesh->totloop,
|
||||
false);
|
||||
|
||||
/* Deformation coords. */
|
||||
co_.reserve(mesh->totvert);
|
||||
|
@@ -26,12 +26,16 @@
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_vec_types.h"
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_buffer.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_sort.h"
|
||||
#include "BLI_sort_utils.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "BLI_memarena.h"
|
||||
|
||||
@@ -194,6 +198,270 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct DiskCycleSortData {
|
||||
float th;
|
||||
int i, elem;
|
||||
const float *co;
|
||||
} DiskCycleSortData;
|
||||
|
||||
/**
|
||||
* Calculate a normal from a vertex cloud.
|
||||
*
|
||||
* \note We could make a higher quality version that takes all vertices into account.
|
||||
* Currently it finds 4 outer most points returning its normal.
|
||||
*/
|
||||
static void calc_cloud_normal(DiskCycleSortData *varr,
|
||||
int varr_len,
|
||||
float r_normal[3],
|
||||
float r_center[3],
|
||||
int *r_index_tangent)
|
||||
{
|
||||
const float varr_len_inv = 1.0f / (float)varr_len;
|
||||
|
||||
/* Get the center point and collect vector array since we loop over these a lot. */
|
||||
float center[3] = {0.0f, 0.0f, 0.0f};
|
||||
for (int i = 0; i < varr_len; i++) {
|
||||
madd_v3_v3fl(center, varr[i].co, varr_len_inv);
|
||||
}
|
||||
|
||||
/* Find the 'co_a' point from center. */
|
||||
int co_a_index = 0;
|
||||
const float *co_a = NULL;
|
||||
{
|
||||
float dist_sq_max = -1.0f;
|
||||
for (int i = 0; i < varr_len; i++) {
|
||||
const float dist_sq_test = len_squared_v3v3(varr[i].co, center);
|
||||
if (!(dist_sq_test <= dist_sq_max)) {
|
||||
co_a = varr[i].co;
|
||||
co_a_index = i;
|
||||
dist_sq_max = dist_sq_test;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float dir_a[3];
|
||||
sub_v3_v3v3(dir_a, co_a, center);
|
||||
normalize_v3(dir_a);
|
||||
|
||||
const float *co_b = NULL;
|
||||
float dir_b[3] = {0.0f, 0.0f, 0.0f};
|
||||
{
|
||||
float dist_sq_max = -1.0f;
|
||||
for (int i = 0; i < varr_len; i++) {
|
||||
if (varr[i].co == co_a) {
|
||||
continue;
|
||||
}
|
||||
float dir_test[3];
|
||||
sub_v3_v3v3(dir_test, varr[i].co, center);
|
||||
project_plane_normalized_v3_v3v3(dir_test, dir_test, dir_a);
|
||||
const float dist_sq_test = len_squared_v3(dir_test);
|
||||
if (!(dist_sq_test <= dist_sq_max)) {
|
||||
co_b = varr[i].co;
|
||||
dist_sq_max = dist_sq_test;
|
||||
copy_v3_v3(dir_b, dir_test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (varr_len <= 3) {
|
||||
normal_tri_v3(r_normal, center, co_a, co_b);
|
||||
goto finally;
|
||||
}
|
||||
|
||||
normalize_v3(dir_b);
|
||||
|
||||
const float *co_a_opposite = NULL;
|
||||
const float *co_b_opposite = NULL;
|
||||
|
||||
{
|
||||
float dot_a_min = FLT_MAX;
|
||||
float dot_b_min = FLT_MAX;
|
||||
for (int i = 0; i < varr_len; i++) {
|
||||
const float *co_test = varr[i].co;
|
||||
float dot_test;
|
||||
|
||||
if (co_test != co_a) {
|
||||
dot_test = dot_v3v3(dir_a, co_test);
|
||||
if (dot_test < dot_a_min) {
|
||||
dot_a_min = dot_test;
|
||||
co_a_opposite = co_test;
|
||||
}
|
||||
}
|
||||
|
||||
if (co_test != co_b) {
|
||||
dot_test = dot_v3v3(dir_b, co_test);
|
||||
if (dot_test < dot_b_min) {
|
||||
dot_b_min = dot_test;
|
||||
co_b_opposite = co_test;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
normal_quad_v3(r_normal, co_a, co_b, co_a_opposite, co_b_opposite);
|
||||
|
||||
finally:
|
||||
if (r_center != NULL) {
|
||||
copy_v3_v3(r_center, center);
|
||||
}
|
||||
if (r_index_tangent != NULL) {
|
||||
*r_index_tangent = co_a_index;
|
||||
}
|
||||
}
|
||||
|
||||
static bool build_disk_cycle_face(const MPoly *mpoly,
|
||||
const MLoop *mloop,
|
||||
const MEdge *medge,
|
||||
const MVert *mvert,
|
||||
int vertex_i,
|
||||
MeshElemMap *elem,
|
||||
int *doneset,
|
||||
int *donelen,
|
||||
DiskCycleSortData *sortdata)
|
||||
{
|
||||
*donelen = 0;
|
||||
|
||||
for (int i = 0; i < elem->count; i++) {
|
||||
const MPoly *mp = mpoly + elem->indices[i];
|
||||
unsigned int loops[2];
|
||||
|
||||
if (poly_get_adj_loops_from_vert(mp, mloop, (unsigned int)vertex_i, loops)) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if (loops[j] != (unsigned int)vertex_i) {
|
||||
bool ok = true;
|
||||
|
||||
for (int k = 0; k < *donelen; k++) {
|
||||
if ((unsigned int)doneset[k] == loops[j]) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
doneset[*donelen] = (int)loops[j];
|
||||
sortdata[*donelen].elem = elem->indices[i];
|
||||
sortdata[*donelen].co = mvert[loops[j]].co;
|
||||
(*donelen)++;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("sort error in sort_disk_cycle_face\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return *donelen == elem->count;
|
||||
}
|
||||
|
||||
static bool build_disk_cycle_loop(const MPoly *mpoly,
|
||||
const MLoop *mloop,
|
||||
const MEdge *medge,
|
||||
const MVert *mvert,
|
||||
int vertex_i,
|
||||
MeshElemMap *elem,
|
||||
int *doneset,
|
||||
int *donelen,
|
||||
DiskCycleSortData *sortdata)
|
||||
{
|
||||
*donelen = 0;
|
||||
|
||||
for (int i = 0; i < elem->count; i++) {
|
||||
int l1 = elem->indices[i];
|
||||
const MLoop *ml = mloop + l1;
|
||||
const MEdge *me = medge + ml->e;
|
||||
|
||||
unsigned int v = me->v1 != (unsigned int)vertex_i ? me->v1 : me->v2;
|
||||
|
||||
sortdata[i].co = mvert[v].co;
|
||||
sortdata[i].elem = l1;
|
||||
sortdata[i].i = i;
|
||||
|
||||
(*donelen)++;
|
||||
}
|
||||
|
||||
return *donelen == elem->count;
|
||||
}
|
||||
|
||||
static bool build_disk_cycle_edge(const MPoly *mpoly,
|
||||
const MLoop *mloop,
|
||||
const MEdge *medge,
|
||||
const MVert *mvert,
|
||||
int vertex_i,
|
||||
MeshElemMap *elem,
|
||||
int *doneset,
|
||||
int *donelen,
|
||||
DiskCycleSortData *sortdata)
|
||||
{
|
||||
*donelen = 0;
|
||||
|
||||
for (int i = 0; i < elem->count; i++) {
|
||||
const MEdge *me = medge + elem->indices[i];
|
||||
|
||||
unsigned int v = me->v1 != (unsigned int)vertex_i ? me->v1 : me->v2;
|
||||
|
||||
sortdata[i].co = mvert[v].co;
|
||||
sortdata[i].elem = elem->indices[i];
|
||||
sortdata[i].i = i;
|
||||
|
||||
(*donelen)++;
|
||||
}
|
||||
|
||||
return *donelen == elem->count;
|
||||
}
|
||||
|
||||
static bool sort_disk_cycle(const MPoly *mpoly,
|
||||
const MLoop *mloop,
|
||||
const MEdge *medge,
|
||||
const MVert *mvert,
|
||||
int vertex_i,
|
||||
MeshElemMap *elem,
|
||||
bool is_loops,
|
||||
bool is_edges)
|
||||
{
|
||||
DiskCycleSortData *sortdata = BLI_array_alloca(sortdata, (unsigned int)elem->count);
|
||||
int *doneset = BLI_array_alloca(doneset, (unsigned int)elem->count);
|
||||
int donelen = 0;
|
||||
|
||||
if (is_loops) {
|
||||
if (!build_disk_cycle_face(
|
||||
mpoly, mloop, medge, mvert, vertex_i, elem, doneset, &donelen, sortdata)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (is_edges) {
|
||||
if (!build_disk_cycle_edge(
|
||||
mpoly, mloop, medge, mvert, vertex_i, elem, doneset, &donelen, sortdata)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!build_disk_cycle_loop(
|
||||
mpoly, mloop, medge, mvert, vertex_i, elem, doneset, &donelen, sortdata)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float no[3], cent[3];
|
||||
int vadj;
|
||||
|
||||
calc_cloud_normal(sortdata, donelen, no, cent, &vadj);
|
||||
|
||||
for (int i = 0; i < donelen; i++) {
|
||||
sortdata[i].th = angle_signed_on_axis_v3v3v3_v3(sortdata[vadj].co, cent, sortdata[i].co, no);
|
||||
}
|
||||
|
||||
qsort((void *)sortdata, (size_t)donelen, sizeof(DiskCycleSortData), BLI_sortutil_cmp_float);
|
||||
|
||||
for (int i = 0; i < donelen; i++) {
|
||||
elem->indices[i] = sortdata[i].elem;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a map where the key is the vertex and the value is a list
|
||||
* of polys or loops that use that vertex as a corner. The lists are allocated
|
||||
@@ -203,12 +471,15 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
|
||||
*/
|
||||
static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const MVert *mvert,
|
||||
const MEdge *medge,
|
||||
const MPoly *mpoly,
|
||||
const MLoop *mloop,
|
||||
int totvert,
|
||||
int totpoly,
|
||||
int totloop,
|
||||
const bool do_loops)
|
||||
const bool do_loops,
|
||||
const bool sort_disk_cycles)
|
||||
{
|
||||
MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
|
||||
int *indices, *index_iter;
|
||||
@@ -246,6 +517,12 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
|
||||
}
|
||||
}
|
||||
|
||||
if (sort_disk_cycles) {
|
||||
for (i = 0; i < totvert; i++) {
|
||||
sort_disk_cycle(mpoly, mloop, medge, mvert, i, map + i, do_loops, false);
|
||||
}
|
||||
}
|
||||
|
||||
*r_map = map;
|
||||
*r_mem = indices;
|
||||
}
|
||||
@@ -257,13 +534,26 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
|
||||
*/
|
||||
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const MVert *mvert,
|
||||
const MEdge *medge,
|
||||
const MPoly *mpoly,
|
||||
const MLoop *mloop,
|
||||
int totvert,
|
||||
int totpoly,
|
||||
int totloop)
|
||||
int totloop,
|
||||
const bool sort_disk_cycles)
|
||||
{
|
||||
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, false);
|
||||
mesh_vert_poly_or_loop_map_create(r_map,
|
||||
r_mem,
|
||||
mvert,
|
||||
medge,
|
||||
mpoly,
|
||||
mloop,
|
||||
totvert,
|
||||
totpoly,
|
||||
totloop,
|
||||
false,
|
||||
sort_disk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,13 +563,17 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
|
||||
*/
|
||||
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const MVert *mvert,
|
||||
const MEdge *medge,
|
||||
const MPoly *mpoly,
|
||||
const MLoop *mloop,
|
||||
int totvert,
|
||||
int totpoly,
|
||||
int totloop)
|
||||
int totloop,
|
||||
const bool sort_disk_cycles)
|
||||
{
|
||||
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
|
||||
mesh_vert_poly_or_loop_map_create(
|
||||
r_map, r_mem, mvert, medge, mpoly, mloop, totvert, totpoly, totloop, true, sort_disk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,8 +630,13 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
|
||||
* is a list of edges that use that vertex as an endpoint.
|
||||
* The lists are allocated from one memory pool.
|
||||
*/
|
||||
void BKE_mesh_vert_edge_map_create(
|
||||
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
|
||||
void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map,
|
||||
int **r_mem,
|
||||
const MVert *mvert,
|
||||
const MEdge *medge,
|
||||
int totvert,
|
||||
int totedge,
|
||||
bool sort_disk_cycles)
|
||||
{
|
||||
MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
|
||||
int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
|
||||
@@ -371,6 +670,12 @@ void BKE_mesh_vert_edge_map_create(
|
||||
map[v[1]].count++;
|
||||
}
|
||||
|
||||
if (sort_disk_cycles) {
|
||||
for (i = 0; i < totvert; i++) {
|
||||
sort_disk_cycle(NULL, NULL, medge, mvert, i, map + i, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
*r_map = map;
|
||||
*r_mem = indices;
|
||||
}
|
||||
|
@@ -379,8 +379,16 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh,
|
||||
|
||||
/* Can we optimize by reusing an old `pmap`? How do we know an old `pmap` is stale? */
|
||||
/* When called by `MOD_array.c` the `cddm` has just been created, so it has no valid `pmap`. */
|
||||
BKE_mesh_vert_poly_map_create(
|
||||
&poly_map, &poly_map_mem, mesh->mpoly, mesh->mloop, totvert, totpoly, totloop);
|
||||
BKE_mesh_vert_poly_map_create(&poly_map,
|
||||
&poly_map_mem,
|
||||
mesh->mvert,
|
||||
mesh->medge,
|
||||
mesh->mpoly,
|
||||
mesh->mloop,
|
||||
totvert,
|
||||
totpoly,
|
||||
totloop,
|
||||
false);
|
||||
} /* done preparing for fast poly compare */
|
||||
|
||||
mp = mesh->mpoly;
|
||||
|
@@ -41,7 +41,8 @@
|
||||
|
||||
#include "MOD_modifiertypes.h"
|
||||
|
||||
Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mmd,
|
||||
Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(Object *ob,
|
||||
MirrorModifierData *mmd,
|
||||
const Mesh *mesh,
|
||||
int axis,
|
||||
const float plane_co[3],
|
||||
@@ -58,7 +59,8 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm
|
||||
BMIter viter;
|
||||
BMVert *v, *v_next;
|
||||
|
||||
bm = BKE_mesh_to_bmesh_ex(mesh,
|
||||
bm = BKE_mesh_to_bmesh_ex(ob,
|
||||
mesh,
|
||||
&(struct BMeshCreateParams){0},
|
||||
&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
@@ -102,7 +104,8 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
|
||||
const int axis,
|
||||
const float dist)
|
||||
{
|
||||
BMesh *bm = BKE_mesh_to_bmesh_ex(mesh,
|
||||
BMesh *bm = BKE_mesh_to_bmesh_ex(NULL,
|
||||
mesh,
|
||||
&(struct BMeshCreateParams){
|
||||
.use_toolflags = 1,
|
||||
},
|
||||
@@ -121,6 +124,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
|
||||
true);
|
||||
|
||||
BM_mesh_bm_to_me(bmain,
|
||||
NULL,
|
||||
bm,
|
||||
mesh,
|
||||
(&(struct BMeshToMeshParams){
|
||||
@@ -207,7 +211,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
|
||||
Mesh *mesh_bisect = NULL;
|
||||
if (do_bisect) {
|
||||
mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(
|
||||
mmd, mesh, axis, plane_co, plane_no);
|
||||
ob, mmd, mesh, axis, plane_co, plane_no);
|
||||
mesh = mesh_bisect;
|
||||
}
|
||||
|
||||
|
@@ -773,9 +773,11 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
|
||||
|
||||
BKE_mesh_vert_edge_map_create(&vert_to_edge_src_map,
|
||||
&vert_to_edge_src_map_mem,
|
||||
NULL,
|
||||
edges_src,
|
||||
num_verts_src,
|
||||
num_edges_src);
|
||||
num_edges_src,
|
||||
false);
|
||||
|
||||
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
|
||||
nearest.index = -1;
|
||||
@@ -1431,19 +1433,25 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
|
||||
if (use_from_vert) {
|
||||
BKE_mesh_vert_loop_map_create(&vert_to_loop_map_src,
|
||||
&vert_to_loop_map_src_buff,
|
||||
verts_src,
|
||||
edges_src,
|
||||
polys_src,
|
||||
loops_src,
|
||||
num_verts_src,
|
||||
num_polys_src,
|
||||
num_loops_src);
|
||||
num_loops_src,
|
||||
false);
|
||||
if (mode & MREMAP_USE_POLY) {
|
||||
BKE_mesh_vert_poly_map_create(&vert_to_poly_map_src,
|
||||
&vert_to_poly_map_src_buff,
|
||||
verts_src,
|
||||
edges_src,
|
||||
polys_src,
|
||||
loops_src,
|
||||
num_verts_src,
|
||||
num_polys_src,
|
||||
num_loops_src);
|
||||
num_loops_src,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "BKE_mesh_remesh_voxel.h" /* own include */
|
||||
#include "BKE_mesh_runtime.h"
|
||||
|
||||
@@ -65,17 +66,28 @@ using blender::MutableSpan;
|
||||
using blender::Span;
|
||||
|
||||
#ifdef WITH_QUADRIFLOW
|
||||
static Mesh *remesh_quadriflow(const Mesh *input_mesh,
|
||||
int target_faces,
|
||||
int seed,
|
||||
bool preserve_sharp,
|
||||
bool preserve_boundary,
|
||||
bool adaptive_scale,
|
||||
void (*update_cb)(void *, float progress, int *cancel),
|
||||
void *update_cb_data)
|
||||
ATTR_NO_OPT static Mesh *remesh_quadriflow(const Mesh *input_mesh,
|
||||
int target_faces,
|
||||
int seed,
|
||||
bool preserve_sharp,
|
||||
bool preserve_boundary,
|
||||
bool adaptive_scale,
|
||||
void (*update_cb)(void *, float progress, int *cancel),
|
||||
void *update_cb_data)
|
||||
{
|
||||
/* Ensure that the triangulated mesh data is up to data */
|
||||
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh);
|
||||
MeshElemMap *epmap = nullptr;
|
||||
int *epmem = nullptr;
|
||||
|
||||
BKE_mesh_edge_poly_map_create(&epmap,
|
||||
&epmem,
|
||||
input_mesh->medge,
|
||||
input_mesh->totedge,
|
||||
input_mesh->mpoly,
|
||||
input_mesh->totpoly,
|
||||
input_mesh->mloop,
|
||||
input_mesh->totloop);
|
||||
|
||||
/* Gather the required data for export to the internal quadriflow mesh format. */
|
||||
MVertTri *verttri = (MVertTri *)MEM_callocN(
|
||||
@@ -86,17 +98,63 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
|
||||
const int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
|
||||
const int totverts = input_mesh->totvert;
|
||||
Array<float3> verts(totverts);
|
||||
Array<int> faces(totfaces * 3);
|
||||
Array<QuadriflowFace> faces(totfaces);
|
||||
|
||||
for (const int i : IndexRange(totverts)) {
|
||||
verts[i] = input_mesh->mvert[i].co;
|
||||
}
|
||||
|
||||
int *fsets = (int *)CustomData_get_layer(&input_mesh->pdata, CD_SCULPT_FACE_SETS);
|
||||
|
||||
for (const int i : IndexRange(totfaces)) {
|
||||
MVertTri &vt = verttri[i];
|
||||
faces[i * 3] = vt.tri[0];
|
||||
faces[i * 3 + 1] = vt.tri[1];
|
||||
faces[i * 3 + 2] = vt.tri[2];
|
||||
faces[i].eflag[0] = faces[i].eflag[1] = faces[i].eflag[2] = 0;
|
||||
|
||||
faces[i].v[0] = vt.tri[0];
|
||||
faces[i].v[1] = vt.tri[1];
|
||||
faces[i].v[2] = vt.tri[2];
|
||||
|
||||
for (const int j : IndexRange(3)) {
|
||||
MLoop *l = input_mesh->mloop + looptri[i].tri[j];
|
||||
MEdge *e = input_mesh->medge + l->e;
|
||||
|
||||
if (e->flag & ME_SHARP) {
|
||||
faces[i].eflag[j] |= QFLOW_CONSTRAINED;
|
||||
continue;
|
||||
}
|
||||
|
||||
MeshElemMap *melem = epmap + looptri[i].poly;
|
||||
|
||||
if (melem->count == 1) {
|
||||
faces[i].eflag[j] |= QFLOW_CONSTRAINED;
|
||||
continue;
|
||||
}
|
||||
|
||||
int fset = 0;
|
||||
int mat_nr = 0;
|
||||
|
||||
for (int k : IndexRange(melem->count)) {
|
||||
MPoly *p = input_mesh->mpoly + melem->indices[k];
|
||||
|
||||
if (k > 0 && p->mat_nr != mat_nr) {
|
||||
faces[i].eflag[j] |= QFLOW_CONSTRAINED;
|
||||
continue;
|
||||
}
|
||||
|
||||
mat_nr = (int)p->mat_nr;
|
||||
|
||||
if (fsets) {
|
||||
int fset2 = fsets[melem->indices[k]];
|
||||
|
||||
if (k > 0 && abs(fset) != abs(fset2)) {
|
||||
faces[i].eflag[j] |= QFLOW_CONSTRAINED;
|
||||
break;
|
||||
}
|
||||
|
||||
fset = fset2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill out the required input data */
|
||||
@@ -158,6 +216,14 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
|
||||
MEM_freeN(qrd.out_faces);
|
||||
MEM_freeN(qrd.out_verts);
|
||||
|
||||
if (epmap) {
|
||||
MEM_freeN((void *)epmap);
|
||||
}
|
||||
|
||||
if (epmem) {
|
||||
MEM_freeN((void *)epmem);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
#endif
|
||||
@@ -415,7 +481,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
|
||||
|
||||
BMeshFromMeshParams bmesh_from_mesh_params{};
|
||||
bmesh_from_mesh_params.calc_face_normal = true;
|
||||
BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
|
||||
BM_mesh_bm_from_me(NULL, bm, mesh, &bmesh_from_mesh_params);
|
||||
|
||||
BMVert *v;
|
||||
BMEdge *ed, *ed_next;
|
||||
@@ -449,7 +515,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
|
||||
if (BM_elem_flag_test(ed, BM_ELEM_TAG)) {
|
||||
float co[3];
|
||||
mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
|
||||
BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true);
|
||||
BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true, false);
|
||||
copy_v3_v3(vc->co, co);
|
||||
}
|
||||
}
|
||||
|
@@ -33,22 +33,31 @@
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_ccg.h"
|
||||
#include "BKE_cdderivedmesh.h"
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "BKE_mesh_runtime.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_multires.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_paint.h"
|
||||
#include "BKE_pbvh.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_subdiv.h"
|
||||
#include "BKE_subdiv_ccg.h"
|
||||
#include "BKE_subdiv_eval.h"
|
||||
#include "BKE_subsurf.h"
|
||||
|
||||
#include "BKE_object.h"
|
||||
@@ -57,6 +66,8 @@
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
#include "multires_inline.h"
|
||||
#include "multires_reshape.h"
|
||||
|
||||
#include <math.h>
|
||||
@@ -846,17 +857,461 @@ static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, int x, int y
|
||||
|
||||
typedef struct MultiresThreadedData {
|
||||
DispOp op;
|
||||
MultiResSpace bmop;
|
||||
BMesh *bm;
|
||||
int lvl;
|
||||
CCGElem **gridData, **subGridData;
|
||||
CCGKey *key;
|
||||
CCGKey *sub_key;
|
||||
Subdiv *sd;
|
||||
MPoly *mpoly;
|
||||
MDisps *mdisps;
|
||||
GridPaintMask *grid_paint_mask;
|
||||
int *gridOffset;
|
||||
int cd_mdisps_off, cd_mask_off;
|
||||
int gridSize, dGridSize, dSkip;
|
||||
float (*smat)[3];
|
||||
bool has_grid_mask;
|
||||
} MultiresThreadedData;
|
||||
|
||||
Object *multires_dump_grids_bmesh(Object *bmob, BMesh *bm)
|
||||
{
|
||||
if (!CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
|
||||
printf("multires_dump_grids_bmesh: error: no multires grids\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool spaceset = false;
|
||||
|
||||
if (bm->multiresSpace != MULTIRES_SPACE_ABSOLUTE) {
|
||||
BKE_multires_bmesh_space_set(bmob, bm, MULTIRES_SPACE_ABSOLUTE);
|
||||
spaceset = true;
|
||||
}
|
||||
|
||||
Main *bmain = G.main;
|
||||
char *name = "multires_dump";
|
||||
|
||||
bContext *ctx = CTX_create();
|
||||
CTX_data_main_set(ctx, bmain);
|
||||
CTX_wm_manager_set(ctx, G.main->wm.first);
|
||||
CTX_data_scene_set(ctx, G.main->scenes.first);
|
||||
|
||||
ViewLayer *view_layer = CTX_data_view_layer(ctx);
|
||||
Object *ob = BKE_object_add_only_object(bmain, OB_MESH, name);
|
||||
LayerCollection *layer_collection;
|
||||
|
||||
ob->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, name);
|
||||
DEG_id_tag_update_ex(
|
||||
bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
||||
// DEG_id_tag_update_ex(
|
||||
// bmain, &ob->data, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
||||
|
||||
layer_collection = BKE_layer_collection_get_active(view_layer);
|
||||
BKE_collection_object_add(bmain, layer_collection->collection, ob);
|
||||
|
||||
DEG_id_type_tag(bmain, ID_OB);
|
||||
DEG_relations_tag_update(bmain);
|
||||
if (ob->data != NULL) {
|
||||
DEG_id_tag_update_ex(bmain, (ID *)ob->data, ID_RECALC_EDITORS);
|
||||
}
|
||||
|
||||
ob->modifiers.first = ob->modifiers.last = NULL;
|
||||
zero_v3(ob->loc);
|
||||
|
||||
printf("users: %d\n", ob->id.us);
|
||||
|
||||
Mesh *me = ob->data;
|
||||
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
|
||||
int cd_mdisp_off = CustomData_get_offset(&bm->ldata, CD_MDISPS);
|
||||
int dimen = 0;
|
||||
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BMLoop *l = f->l_first;
|
||||
MDisps *md = BM_ELEM_CD_GET_VOID_P(l, cd_mdisp_off);
|
||||
dimen = (int)floor(sqrt(md->totdisp) + 0.00001);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dimen) {
|
||||
printf("multires_dump_grids_bmesh: error: corrupted multires data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int totvert = bm->totloop * dimen * dimen;
|
||||
int totface = bm->totloop * (dimen - 1) * (dimen - 1);
|
||||
int totloop = totface * 4;
|
||||
|
||||
CustomData_free(&me->vdata, me->totvert);
|
||||
CustomData_free(&me->edata, me->totedge);
|
||||
CustomData_free(&me->fdata, me->totface);
|
||||
CustomData_free(&me->ldata, me->totloop);
|
||||
CustomData_free(&me->pdata, me->totpoly);
|
||||
|
||||
me->totvert = totvert;
|
||||
me->totpoly = totface;
|
||||
me->totloop = totloop;
|
||||
me->totedge = totvert + totface;
|
||||
me->totface = 0;
|
||||
me->act_face = -1;
|
||||
|
||||
EdgeHash *eh = BLI_edgehash_new_ex("multires_dump_bmesh", me->totedge);
|
||||
|
||||
MVert *mvert = me->totvert ?
|
||||
MEM_callocN(sizeof(MVert) * me->totvert, "multires_dump_grids_bmesh.vert") :
|
||||
NULL;
|
||||
MEdge *medge = me->totedge ?
|
||||
MEM_callocN(sizeof(MEdge) * me->totedge, "multires_dump_grids_bmesh.edge") :
|
||||
NULL;
|
||||
MLoop *mloop = me->totloop ?
|
||||
MEM_callocN(sizeof(MLoop) * me->totloop, "multires_dump_grids_bmesh.loop") :
|
||||
NULL;
|
||||
MPoly *mpoly = me->totpoly ?
|
||||
MEM_callocN(sizeof(MPoly) * me->totpoly, "multires_dump_grids_bmesh.poly") :
|
||||
NULL;
|
||||
|
||||
me->cd_flag = 0;
|
||||
|
||||
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
|
||||
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
|
||||
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
|
||||
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
|
||||
|
||||
BKE_mesh_update_customdata_pointers(me, 0);
|
||||
|
||||
int loopi = 0;
|
||||
int outli = 0;
|
||||
int medi = 0;
|
||||
|
||||
#define VINDEX(i, j) (loopi * dimen * dimen + ((j)*dimen + (i)))
|
||||
|
||||
// CustomData_daata_
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BMLoop *l = f->l_first;
|
||||
do {
|
||||
MDisps *md = BM_ELEM_CD_GET_VOID_P(l, cd_mdisp_off);
|
||||
|
||||
for (int i = 0; i < dimen; i++) {
|
||||
for (int j = 0; j < dimen; j++) {
|
||||
int vidx = loopi * dimen * dimen + (j * dimen + i);
|
||||
int idx = j * dimen + i;
|
||||
float *co = md->disps[idx];
|
||||
|
||||
MVert *mv = mvert + vidx;
|
||||
copy_v3_v3(mv->co, co);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < dimen - 1; i++) {
|
||||
for (int j = 0; j < dimen - 1; j++) {
|
||||
// do face
|
||||
int fidx = loopi * (dimen - 1) * (dimen - 1) + (j * (dimen - 1) + i);
|
||||
MPoly *mp = mpoly + fidx;
|
||||
|
||||
mp->totloop = 4;
|
||||
mp->loopstart = outli;
|
||||
|
||||
MLoop *ml = mloop + outli;
|
||||
|
||||
ml[0].v = VINDEX(i, j);
|
||||
ml[1].v = VINDEX(i, j + 1);
|
||||
ml[2].v = VINDEX(i + 1, j + 1);
|
||||
ml[3].v = VINDEX(i + 1, j);
|
||||
|
||||
for (int i2 = 0; i2 < 4; i2++) {
|
||||
int a = ml[i2].v, b = ml[(i2 + 1) % 4].v;
|
||||
int e;
|
||||
|
||||
if (!BLI_edgehash_haskey(eh, a, b)) {
|
||||
BLI_edgehash_insert(eh, a, b, (void *)medi);
|
||||
e = medi;
|
||||
|
||||
MEdge *med = medge + medi;
|
||||
|
||||
med->v1 = a;
|
||||
med->v2 = b;
|
||||
|
||||
medi++;
|
||||
}
|
||||
else {
|
||||
e = (int)BLI_edgehash_lookup(eh, a, b);
|
||||
}
|
||||
|
||||
ml[i2].e = e;
|
||||
}
|
||||
|
||||
outli += 4;
|
||||
}
|
||||
}
|
||||
|
||||
loopi++;
|
||||
l = l->next;
|
||||
} while (l != f->l_first);
|
||||
}
|
||||
|
||||
for (int i = 0; i < me->totpoly; i++) {
|
||||
if (!mpoly[i].totloop) {
|
||||
printf("error 1! %d %d\n", i, me->totpoly);
|
||||
}
|
||||
if (mpoly[i].loopstart >= me->totloop) {
|
||||
printf(
|
||||
"error 2! %d %d l: %d totl: %d\n", i, me->totpoly, mpoly[i].loopstart, mpoly[i].totloop);
|
||||
}
|
||||
}
|
||||
|
||||
if (spaceset) {
|
||||
BKE_multires_bmesh_space_set(bmob, bm, MULTIRES_SPACE_TANGENT);
|
||||
}
|
||||
|
||||
BKE_mesh_calc_normals(me);
|
||||
BKE_mesh_tessface_calc(me);
|
||||
|
||||
return ob;
|
||||
}
|
||||
|
||||
//#define LIMIT_MAX_DISPLACEMENT
|
||||
|
||||
static void multires_bmesh_space_set_cb(void *__restrict userdata,
|
||||
const int pidx,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
MultiresThreadedData *tdata = userdata;
|
||||
|
||||
int cd_mdisps_off = tdata->cd_mdisps_off;
|
||||
BMesh *bm = tdata->bm;
|
||||
MultiResSpace op = tdata->bmop;
|
||||
BMFace *f = bm->ftable[pidx];
|
||||
int gridSize = tdata->gridSize;
|
||||
|
||||
int S, x, y;
|
||||
|
||||
BMLoop *l;
|
||||
|
||||
#ifdef LIMIT_MAX_DISPLACEMENT
|
||||
l = f->l_first;
|
||||
float cent[3];
|
||||
int tot = 0;
|
||||
|
||||
// get face center to calculate maximum allowable displacement length
|
||||
zero_v3(cent);
|
||||
do {
|
||||
add_v3_v3(cent, l->v->co);
|
||||
tot++;
|
||||
l = l->next;
|
||||
} while (l != f->l_first);
|
||||
|
||||
mul_v3_fl(cent, 1.0f / (float)tot);
|
||||
#endif
|
||||
|
||||
l = f->l_first;
|
||||
S = 0;
|
||||
do {
|
||||
MDisps *mdisp = BM_ELEM_CD_GET_VOID_P(l, cd_mdisps_off);
|
||||
float(*dispgrid)[3] = NULL;
|
||||
|
||||
dispgrid = mdisp->disps;
|
||||
|
||||
#ifdef LIMIT_MAX_DISPLACEMENT
|
||||
/*try to limit numerical instability by clamping max displacement*/
|
||||
|
||||
float maxlen = len_v3v3(l->v->co, cent) * 15.0f;
|
||||
maxlen = MAX2(maxlen, 0.00001f);
|
||||
#endif
|
||||
|
||||
for (y = 0; y < gridSize; y++) {
|
||||
for (x = 0; x < gridSize; x++) {
|
||||
float sco[8], udv[3], vdv[3];
|
||||
float *data = dispgrid[gridSize * y + x];
|
||||
float mat[3][3], disp[3];
|
||||
|
||||
float grid_u = (float)x / (float)(gridSize - 1);
|
||||
float grid_v = (float)y / (float)(gridSize - 1);
|
||||
float u, v;
|
||||
|
||||
int corner = S;
|
||||
if (f->len == 4) {
|
||||
BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, &u, &v);
|
||||
}
|
||||
else {
|
||||
u = 1.0 - grid_v;
|
||||
v = 1.0 - grid_u;
|
||||
}
|
||||
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(tdata->sd, l->head.index, u, v, sco, udv, vdv);
|
||||
BKE_multires_construct_tangent_matrix(mat, udv, vdv, f->len == 4 ? corner : 0);
|
||||
|
||||
copy_v3_v3(disp, data);
|
||||
|
||||
switch (op) {
|
||||
case MULTIRES_SPACE_ABSOLUTE:
|
||||
/* Convert displacement to object space
|
||||
* and add to grid points */
|
||||
mul_v3_m3v3(disp, mat, data);
|
||||
add_v3_v3v3(data, disp, sco);
|
||||
break;
|
||||
case MULTIRES_SPACE_TANGENT:
|
||||
/* Calculate displacement between new and old
|
||||
* grid points and convert to tangent space */
|
||||
invert_m3(mat);
|
||||
|
||||
sub_v3_v3v3(disp, data, sco);
|
||||
mul_v3_m3v3(data, mat, disp);
|
||||
|
||||
// try to prevent errors
|
||||
float len = len_v3(data);
|
||||
#ifdef LIMIT_MAX_DISPLACEMENT
|
||||
if (len > maxlen) {
|
||||
mul_v3_fl(data, maxlen / len);
|
||||
}
|
||||
else if (isnan(len)) {
|
||||
zero_v3(data);
|
||||
}
|
||||
#else
|
||||
if (isnan(len)) {
|
||||
zero_v3(data);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
S++;
|
||||
l = l->next;
|
||||
} while (l != f->l_first);
|
||||
}
|
||||
|
||||
/* The original version of this function was broken (and subsequently removed)
|
||||
because it didn't properly set the subdivision level; it also used the old
|
||||
multires system. The new subdiv API is now used instead.
|
||||
*/
|
||||
void BKE_multires_bmesh_space_set(Object *ob, BMesh *bm, int mode)
|
||||
{
|
||||
if (!bm->totface || !CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get multires settings
|
||||
MultiresModifierData *mmd = bm->haveMultiResSettings ? &bm->multires : NULL;
|
||||
|
||||
if (!mmd && ob) {
|
||||
mmd = get_multires_modifier(NULL, ob, true);
|
||||
}
|
||||
|
||||
if (!mmd || !CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// cache multires settings in bmesh
|
||||
bm->multiresSpace = mode;
|
||||
|
||||
// create temporary mesh structure
|
||||
Mesh _me, *me = &_me;
|
||||
memset(me, 0, sizeof(Mesh));
|
||||
CustomData_reset(&me->vdata);
|
||||
CustomData_reset(&me->edata);
|
||||
CustomData_reset(&me->ldata);
|
||||
CustomData_reset(&me->fdata);
|
||||
CustomData_reset(&me->pdata);
|
||||
|
||||
CustomData_MeshMasks extra = CD_MASK_DERIVEDMESH;
|
||||
extra.lmask |= CD_MASK_MDISPS;
|
||||
|
||||
BM_mesh_bm_to_me_for_eval(bm, me, &extra);
|
||||
SubdivSettings settings2;
|
||||
|
||||
// copy the settings and then set subdivision level to max
|
||||
MultiresModifierData mmdcpy = *mmd;
|
||||
mmdcpy.lvl = mmdcpy.sculptlvl = mmdcpy.renderlvl = mmdcpy.totlvl;
|
||||
|
||||
// set up subdivision surface
|
||||
BKE_multires_subdiv_settings_init(&settings2, &mmdcpy);
|
||||
Subdiv *sd = BKE_subdiv_new_from_mesh(&settings2, me);
|
||||
BKE_subdiv_eval_begin_from_mesh(sd, me, NULL);
|
||||
|
||||
// create a fake object with .sculpt set to NULL
|
||||
Object fakeob;
|
||||
if (ob) {
|
||||
fakeob = *ob;
|
||||
fakeob.sculpt = NULL;
|
||||
}
|
||||
else {
|
||||
memset(&fakeob, 0, sizeof(fakeob));
|
||||
fakeob.data = me;
|
||||
BLI_addtail(&fakeob.modifiers, &mmdcpy);
|
||||
}
|
||||
|
||||
int i, gridSize;
|
||||
int totpoly = bm->totface;
|
||||
|
||||
// force paranoia recalc of indices and lookup tables
|
||||
bm->elem_index_dirty |= BM_FACE;
|
||||
bm->elem_table_dirty |= BM_FACE;
|
||||
|
||||
BM_mesh_elem_index_ensure(bm, BM_FACE);
|
||||
BM_mesh_elem_table_ensure(bm, BM_FACE);
|
||||
|
||||
gridSize = multires_side_tot[mmd->totlvl];
|
||||
|
||||
int cd_disp_off = CustomData_get_offset(&bm->ldata, CD_MDISPS);
|
||||
|
||||
BMFace *f;
|
||||
BMIter iter;
|
||||
i = 0;
|
||||
|
||||
/*check that all grids are allocated and also set some indices*/
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BMIter iter2;
|
||||
BMLoop *l;
|
||||
|
||||
f->head.index = i;
|
||||
|
||||
BM_ITER_ELEM (l, &iter2, f, BM_LOOPS_OF_FACE) {
|
||||
MDisps *mdisp = BM_ELEM_CD_GET_VOID_P(l, cd_disp_off);
|
||||
|
||||
/* allocate new disps, this can happen with newly created faces */
|
||||
if (!mdisp->disps) {
|
||||
multires_reallocate_mdisps(1, mdisp, mmd->totlvl);
|
||||
}
|
||||
|
||||
l->head.index = i;
|
||||
|
||||
if (f->len != 4) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (f->len == 4) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// do the space conversion
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = CCG_TASK_LIMIT;
|
||||
|
||||
MultiresThreadedData data = {
|
||||
.bmop = mode,
|
||||
.sd = sd,
|
||||
.lvl = mmd->totlvl,
|
||||
.bm = bm,
|
||||
.cd_mdisps_off = cd_disp_off,
|
||||
.gridSize = gridSize,
|
||||
};
|
||||
|
||||
BLI_task_parallel_range(0, totpoly, &data, multires_bmesh_space_set_cb, &settings);
|
||||
|
||||
BKE_mesh_free_data_for_undo(me);
|
||||
BKE_subdiv_free(sd);
|
||||
|
||||
bm->elem_index_dirty |= BM_FACE | BM_LOOP;
|
||||
bm->elem_table_dirty |= BM_FACE | BM_LOOP;
|
||||
}
|
||||
|
||||
static void multires_disp_run_cb(void *__restrict userdata,
|
||||
const int pidx,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
@@ -1218,7 +1673,7 @@ void multires_stitch_grids(Object *ob)
|
||||
int num_faces;
|
||||
BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces);
|
||||
if (num_faces) {
|
||||
BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
|
||||
// XXX BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
|
||||
MEM_freeN(faces);
|
||||
}
|
||||
}
|
||||
@@ -1334,7 +1789,7 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
|
||||
|
||||
urat = u - x;
|
||||
vrat = v - y;
|
||||
uopp = 1 - urat;
|
||||
uopp = 1.0f - urat;
|
||||
|
||||
mul_v3_v3fl(d[0], disps[y * st + x], uopp);
|
||||
mul_v3_v3fl(d[1], disps[y * st + x2], urat);
|
||||
@@ -1343,7 +1798,7 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
|
||||
|
||||
add_v3_v3v3(d2[0], d[0], d[1]);
|
||||
add_v3_v3v3(d2[1], d[2], d[3]);
|
||||
mul_v3_fl(d2[0], 1 - vrat);
|
||||
mul_v3_fl(d2[0], 1.0f - vrat);
|
||||
mul_v3_fl(d2[1], vrat);
|
||||
|
||||
add_v3_v3v3(out, d2[0], d2[1]);
|
||||
|
@@ -292,6 +292,12 @@ void multiresModifier_base_apply(struct Depsgraph *depsgraph,
|
||||
multires_reshape_apply_base_update_mesh_coords(&reshape_context);
|
||||
multires_reshape_apply_base_refit_base_mesh(&reshape_context);
|
||||
|
||||
/**
|
||||
* Tag update so deform modifiers (e.g. smooth corrective)
|
||||
* get updated original coordinates
|
||||
*/
|
||||
DEG_id_tag_update((ID *)object, ID_RECALC_GEOMETRY);
|
||||
|
||||
/* Reshape to the stored final state.
|
||||
* Not that the base changed, so the subdiv is to be refined to the new positions. Unfortunately,
|
||||
* this can not be done foe entirely cheap: if there were deformation modifiers prior to the
|
||||
|
@@ -87,11 +87,14 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
|
||||
int *pmap_mem;
|
||||
BKE_mesh_vert_poly_map_create(&pmap,
|
||||
&pmap_mem,
|
||||
base_mesh->mvert,
|
||||
base_mesh->medge,
|
||||
base_mesh->mpoly,
|
||||
base_mesh->mloop,
|
||||
base_mesh->totvert,
|
||||
base_mesh->totpoly,
|
||||
base_mesh->totloop);
|
||||
base_mesh->totloop,
|
||||
false);
|
||||
|
||||
float(*origco)[3] = MEM_calloc_arrayN(
|
||||
base_mesh->totvert, sizeof(float[3]), "multires apply base origco");
|
||||
|
@@ -48,6 +48,39 @@
|
||||
#include "atomic_ops.h"
|
||||
#include "subdiv_converter.h"
|
||||
|
||||
|
||||
bool debug_invert_m3_m3(float m1[3][3], const float m2[3][3], const char *func, int line)
|
||||
{
|
||||
float det;
|
||||
int a, b;
|
||||
bool success;
|
||||
|
||||
/* calc adjoint */
|
||||
adjoint_m3_m3(m1, m2);
|
||||
|
||||
/* then determinant old matrix! */
|
||||
det = determinant_m3_array(m2);
|
||||
|
||||
if (det > -0.0001 && det < 0.0001) {
|
||||
fprintf(stderr, "matrix inverse error %s:%i\n\n", func, line);
|
||||
}
|
||||
|
||||
success = (det != 0.0f);
|
||||
|
||||
if (LIKELY(det != 0.0f)) {
|
||||
det = 1.0f / det;
|
||||
for (a = 0; a < 3; a++) {
|
||||
for (b = 0; b < 3; b++) {
|
||||
m1[a][b] *= det;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
//#define invert_m3_m3(m1, m2) debug_invert_m3_m3(m1, m2, __func__, __LINE__)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Local Structs
|
||||
* \{ */
|
||||
|
@@ -315,6 +315,8 @@ void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_contex
|
||||
|
||||
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
|
||||
{
|
||||
ModifierData *md;
|
||||
|
||||
if (reshape_context->need_free_subdiv) {
|
||||
BKE_subdiv_free(reshape_context->subdiv);
|
||||
}
|
||||
|
@@ -881,7 +881,8 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh)
|
||||
.use_toolflags = true,
|
||||
}));
|
||||
|
||||
BM_mesh_bm_from_me(bm,
|
||||
BM_mesh_bm_from_me(NULL,
|
||||
bm,
|
||||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
@@ -1151,6 +1152,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
|
||||
/* Store the new base-mesh as a mesh in context, free bmesh. */
|
||||
context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
|
||||
BM_mesh_bm_to_me(NULL,
|
||||
NULL,
|
||||
bm_base_mesh,
|
||||
context->base_mesh,
|
||||
(&(struct BMeshToMeshParams){
|
||||
|
@@ -51,6 +51,7 @@
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_crazyspace.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_image.h"
|
||||
@@ -67,6 +68,7 @@
|
||||
#include "BKE_pbvh.h"
|
||||
#include "BKE_subdiv_ccg.h"
|
||||
#include "BKE_subsurf.h"
|
||||
#include "BKE_undo_system.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_query.h"
|
||||
@@ -77,6 +79,15 @@
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
// XXX todo: figure out bad cross module refs
|
||||
void SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me);
|
||||
void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
|
||||
void SCULPT_dyntopo_node_layers_add(SculptSession *ss);
|
||||
BMesh *SCULPT_dyntopo_empty_bmesh();
|
||||
void SCULPT_undo_ensure_bmlog(Object *ob);
|
||||
|
||||
static void init_mdyntopo_layer(SculptSession *ss, int totvert);
|
||||
|
||||
static void palette_init_data(ID *id)
|
||||
{
|
||||
Palette *palette = (Palette *)id;
|
||||
@@ -1075,7 +1086,8 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
|
||||
paint->symmetry_flags |= PAINT_SYMM_X;
|
||||
|
||||
/* Make sure at least dyntopo subdivision is enabled */
|
||||
data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
|
||||
data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE | SCULPT_DYNTOPO_CLEANUP |
|
||||
SCULPT_DYNTOPO_ENABLED;
|
||||
}
|
||||
else if ((GpPaint **)r_paint == &ts->gp_paint) {
|
||||
GpPaint *data = MEM_callocN(sizeof(*data), __func__);
|
||||
@@ -1375,20 +1387,23 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
|
||||
|
||||
if (ss->bm) {
|
||||
if (ob->data) {
|
||||
BMIter iter;
|
||||
BMFace *efa;
|
||||
BM_ITER_MESH (efa, &iter, ss->bm, BM_FACES_OF_MESH) {
|
||||
BM_elem_flag_set(efa, BM_ELEM_SMOOTH, ss->bm_smooth_shading);
|
||||
}
|
||||
if (reorder) {
|
||||
BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
|
||||
}
|
||||
BM_mesh_bm_to_me(NULL,
|
||||
ss->bm,
|
||||
ob->data,
|
||||
(&(struct BMeshToMeshParams){
|
||||
.calc_object_remap = false,
|
||||
}));
|
||||
Mesh *me = BKE_object_get_original_mesh(ob);
|
||||
|
||||
BM_mesh_bm_to_me(
|
||||
NULL,
|
||||
NULL,
|
||||
ss->bm,
|
||||
ob->data,
|
||||
(&(struct BMeshToMeshParams){.calc_object_remap = false,
|
||||
/*
|
||||
for memfile undo steps we need to
|
||||
save id and temporary layers
|
||||
*/
|
||||
.copy_temp_cdlayers = true,
|
||||
.ignore_mesh_id_layers = false,
|
||||
.cd_mask_extra = CD_MASK_MESH_ID | CD_MASK_DYNTOPO_VERT
|
||||
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1466,7 +1481,19 @@ void BKE_sculptsession_free(Object *ob)
|
||||
if (ob && ob->sculpt) {
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
if (ss->mdyntopo_verts) {
|
||||
MEM_freeN(ss->mdyntopo_verts);
|
||||
ss->mdyntopo_verts = NULL;
|
||||
}
|
||||
|
||||
if (ss->bm_log && BM_log_free(ss->bm_log, true)) {
|
||||
ss->bm_log = NULL;
|
||||
}
|
||||
|
||||
/*try to save current mesh*/
|
||||
if (ss->bm) {
|
||||
SCULPT_on_sculptsession_bmesh_free(ss);
|
||||
|
||||
BKE_sculptsession_bm_to_me(ob, true);
|
||||
BM_mesh_free(ss->bm);
|
||||
}
|
||||
@@ -1482,10 +1509,6 @@ void BKE_sculptsession_free(Object *ob)
|
||||
MEM_SAFE_FREE(ss->vemap);
|
||||
MEM_SAFE_FREE(ss->vemap_mem);
|
||||
|
||||
if (ss->bm_log) {
|
||||
BM_log_free(ss->bm_log);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(ss->texcache);
|
||||
|
||||
if (ss->tex_pool) {
|
||||
@@ -1608,6 +1631,12 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
|
||||
return false;
|
||||
}
|
||||
|
||||
char BKE_get_fset_boundary_symflag(Object *object)
|
||||
{
|
||||
const Mesh *mesh = BKE_mesh_from_object(object);
|
||||
return mesh->flag & ME_SCULPT_MIRROR_FSET_BOUNDARIES ? mesh->symmetry : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param need_mask: So that the evaluated mesh that is returned has mask data.
|
||||
*/
|
||||
@@ -1621,7 +1650,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
|
||||
Scene *scene = DEG_get_input_scene(depsgraph);
|
||||
Sculpt *sd = scene->toolsettings->sculpt;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const Mesh *me = BKE_object_get_original_mesh(ob);
|
||||
Mesh *me = BKE_object_get_original_mesh(ob);
|
||||
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
|
||||
const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
|
||||
|
||||
@@ -1645,6 +1674,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
|
||||
}
|
||||
|
||||
ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
|
||||
ss->boundary_symmetry = (int)BKE_get_fset_boundary_symflag(ob);
|
||||
|
||||
/* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
|
||||
* so no extra checks is needed here. */
|
||||
@@ -1659,14 +1689,16 @@ static void sculpt_update_object(Depsgraph *depsgraph,
|
||||
/* These are assigned to the base mesh in Multires. This is needed because Face Sets operators
|
||||
* and tools use the Face Sets data from the base mesh when Multires is active. */
|
||||
ss->mvert = me->mvert;
|
||||
ss->mpoly = me->mpoly;
|
||||
ss->medge = me->medge;
|
||||
ss->mloop = me->mloop;
|
||||
ss->mpoly = me->mpoly;
|
||||
}
|
||||
else {
|
||||
ss->totvert = me->totvert;
|
||||
ss->totpoly = me->totpoly;
|
||||
ss->totfaces = me->totpoly;
|
||||
ss->mvert = me->mvert;
|
||||
ss->medge = me->medge;
|
||||
ss->mpoly = me->mpoly;
|
||||
ss->mloop = me->mloop;
|
||||
ss->multires.active = false;
|
||||
@@ -1674,6 +1706,11 @@ static void sculpt_update_object(Depsgraph *depsgraph,
|
||||
ss->multires.level = 0;
|
||||
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
|
||||
ss->vcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
|
||||
|
||||
ss->vdata = &me->vdata;
|
||||
ss->edata = &me->edata;
|
||||
ss->ldata = &me->ldata;
|
||||
ss->pdata = &me->pdata;
|
||||
}
|
||||
|
||||
/* Sculpt Face Sets. */
|
||||
@@ -1686,8 +1723,10 @@ static void sculpt_update_object(Depsgraph *depsgraph,
|
||||
}
|
||||
|
||||
ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
|
||||
ss->fast_draw = (scene->toolsettings->sculpt->flags & SCULPT_FAST_DRAW) != 0;
|
||||
|
||||
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
|
||||
|
||||
BLI_assert(pbvh == ss->pbvh);
|
||||
UNUSED_VARS_NDEBUG(pbvh);
|
||||
|
||||
@@ -1697,8 +1736,16 @@ static void sculpt_update_object(Depsgraph *depsgraph,
|
||||
BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default);
|
||||
|
||||
if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
|
||||
BKE_mesh_vert_poly_map_create(
|
||||
&ss->pmap, &ss->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
|
||||
BKE_mesh_vert_poly_map_create(&ss->pmap,
|
||||
&ss->pmap_mem,
|
||||
me->mvert,
|
||||
me->medge,
|
||||
me->mpoly,
|
||||
me->mloop,
|
||||
me->totvert,
|
||||
me->totpoly,
|
||||
me->totloop,
|
||||
false);
|
||||
}
|
||||
|
||||
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
|
||||
@@ -1793,6 +1840,7 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
|
||||
|
||||
BLI_assert(me_eval != NULL);
|
||||
sculpt_update_object(depsgraph, ob_orig, me_eval, false, false, false);
|
||||
SCULPT_dynamic_topology_sync_layers(ob_orig, me_eval);
|
||||
}
|
||||
|
||||
void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
|
||||
@@ -1809,17 +1857,19 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
|
||||
CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert);
|
||||
BKE_mesh_update_customdata_pointers(orig_me, true);
|
||||
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
||||
SCULPT_dynamic_topology_sync_layers(object, orig_me);
|
||||
}
|
||||
|
||||
/** \warning Expects a fully evaluated depsgraph. */
|
||||
void BKE_sculpt_update_object_for_edit(
|
||||
Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors)
|
||||
{
|
||||
BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
|
||||
|
||||
/* Update from sculpt operators and undo, to update sculpt session
|
||||
* and PBVH after edits. */
|
||||
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
|
||||
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig);
|
||||
Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
|
||||
BLI_assert(me_eval != NULL);
|
||||
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
|
||||
|
||||
BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
|
||||
|
||||
sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, need_colors);
|
||||
}
|
||||
@@ -1896,11 +1946,30 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
|
||||
|
||||
Sculpt *sd = scene->toolsettings->sculpt;
|
||||
if (!sd->detail_size) {
|
||||
sd->detail_size = 12;
|
||||
sd->detail_size = 8.0f;
|
||||
}
|
||||
|
||||
if (!sd->dyntopo_radius_scale) {
|
||||
sd->dyntopo_radius_scale = 1.0f;
|
||||
}
|
||||
|
||||
// we check these flags here in case versioning code fails
|
||||
if (!sd->detail_range || !sd->dyntopo_spacing) {
|
||||
sd->flags |= SCULPT_DYNTOPO_CLEANUP | SCULPT_DYNTOPO_ENABLED;
|
||||
}
|
||||
|
||||
if (!sd->detail_range) {
|
||||
sd->detail_range = 0.4f;
|
||||
}
|
||||
|
||||
if (!sd->detail_percent) {
|
||||
sd->detail_percent = 25;
|
||||
}
|
||||
|
||||
if (!sd->dyntopo_spacing) {
|
||||
sd->dyntopo_spacing = 35;
|
||||
}
|
||||
|
||||
if (sd->constant_detail == 0.0f) {
|
||||
sd->constant_detail = 3.0f;
|
||||
}
|
||||
@@ -2094,14 +2163,21 @@ void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
|
||||
static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
|
||||
{
|
||||
PBVH *pbvh = BKE_pbvh_new();
|
||||
|
||||
BKE_pbvh_set_symmetry(pbvh, 0, (int)BKE_get_fset_boundary_symflag(ob));
|
||||
|
||||
BKE_pbvh_build_bmesh(pbvh,
|
||||
ob->sculpt->bm,
|
||||
ob->sculpt->bm_smooth_shading,
|
||||
ob->sculpt->bm_log,
|
||||
ob->sculpt->cd_vert_node_offset,
|
||||
ob->sculpt->cd_face_node_offset);
|
||||
ob->sculpt->cd_face_node_offset,
|
||||
ob->sculpt->cd_dyn_vert,
|
||||
ob->sculpt->cd_face_areas,
|
||||
ob->sculpt->fast_draw);
|
||||
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
|
||||
pbvh_show_face_sets_set(pbvh, false);
|
||||
|
||||
return pbvh;
|
||||
}
|
||||
|
||||
@@ -2118,17 +2194,21 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
|
||||
|
||||
BKE_sculpt_sync_face_set_visibility(me, NULL);
|
||||
|
||||
BKE_sculptsession_check_mdyntopo(ob->sculpt, me->totvert);
|
||||
|
||||
BKE_pbvh_build_mesh(pbvh,
|
||||
me,
|
||||
me->mpoly,
|
||||
me->mloop,
|
||||
me->mvert,
|
||||
ob->sculpt->mdyntopo_verts,
|
||||
me->totvert,
|
||||
&me->vdata,
|
||||
&me->ldata,
|
||||
&me->pdata,
|
||||
looptri,
|
||||
looptris_num);
|
||||
looptris_num,
|
||||
ob->sculpt->fast_draw);
|
||||
|
||||
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
|
||||
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
|
||||
@@ -2160,18 +2240,50 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
|
||||
&key,
|
||||
(void **)subdiv_ccg->grid_faces,
|
||||
subdiv_ccg->grid_flag_mats,
|
||||
subdiv_ccg->grid_hidden);
|
||||
subdiv_ccg->grid_hidden,
|
||||
ob->sculpt->fast_draw);
|
||||
|
||||
BKE_sculptsession_check_mdyntopo(ob->sculpt, BKE_pbvh_get_grid_num_vertices(pbvh));
|
||||
|
||||
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
|
||||
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
|
||||
return pbvh;
|
||||
}
|
||||
|
||||
bool BKE_sculptsession_check_mdyntopo(SculptSession *ss, int totvert)
|
||||
{
|
||||
if (!ss->bm && (!ss->mdyntopo_verts || totvert != ss->mdyntopo_verts_size)) {
|
||||
init_mdyntopo_layer(ss, totvert);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void init_mdyntopo_layer(SculptSession *ss, int totvert)
|
||||
{
|
||||
if (ss->mdyntopo_verts) {
|
||||
MEM_freeN(ss->mdyntopo_verts);
|
||||
}
|
||||
|
||||
ss->mdyntopo_verts = MEM_calloc_arrayN(totvert, sizeof(*ss->mdyntopo_verts), "mdyntopo_verts");
|
||||
ss->mdyntopo_verts_size = totvert;
|
||||
|
||||
MDynTopoVert *mv = ss->mdyntopo_verts;
|
||||
|
||||
for (int i = 0; i < totvert; i++, mv++) {
|
||||
mv->flag = DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_VALENCE | DYNVERT_NEED_DISK_SORT;
|
||||
mv->stroke_id = -1;
|
||||
}
|
||||
}
|
||||
PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
|
||||
{
|
||||
if (ob == NULL || ob->sculpt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Scene *scene = DEG_get_input_scene(depsgraph);
|
||||
|
||||
bool respect_hide = true;
|
||||
if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
|
||||
if (!(BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob))) {
|
||||
@@ -2181,6 +2293,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
|
||||
|
||||
PBVH *pbvh = ob->sculpt->pbvh;
|
||||
if (pbvh != NULL) {
|
||||
SCULPT_update_flat_vcol_shading(ob, scene);
|
||||
|
||||
/* NOTE: It is possible that grids were re-allocated due to modifier
|
||||
* stack. Need to update those pointers. */
|
||||
if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
|
||||
@@ -2191,14 +2305,59 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
|
||||
BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg);
|
||||
}
|
||||
}
|
||||
else if (BKE_pbvh_type(pbvh) == PBVH_BMESH) {
|
||||
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
|
||||
|
||||
SCULPT_dynamic_topology_sync_layers(ob, BKE_object_get_original_mesh(ob));
|
||||
}
|
||||
return pbvh;
|
||||
}
|
||||
|
||||
if (ob->sculpt->bm != NULL) {
|
||||
/* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
|
||||
pbvh = build_pbvh_for_dynamic_topology(ob);
|
||||
|
||||
ob->sculpt->pbvh = pbvh;
|
||||
}
|
||||
else {
|
||||
#if 1 // def WHEN_GLOBAL_UNDO_WORKS
|
||||
/*detect if we are loading from an undo memfile step*/
|
||||
Mesh *mesh_orig = BKE_object_get_original_mesh(ob);
|
||||
bool is_dyntopo = (mesh_orig->flag & ME_SCULPT_DYNAMIC_TOPOLOGY);
|
||||
|
||||
if (is_dyntopo) {
|
||||
BMesh *bm = SCULPT_dyntopo_empty_bmesh();
|
||||
|
||||
ob->sculpt->bm = bm;
|
||||
|
||||
BM_mesh_bm_from_me(NULL,
|
||||
bm,
|
||||
mesh_orig,
|
||||
(&(struct BMeshFromMeshParams){.calc_face_normal = true,
|
||||
.use_shapekey = true,
|
||||
.active_shapekey = ob->shapenr,
|
||||
.ignore_id_layers = false,
|
||||
.copy_temp_cdlayers = true,
|
||||
.cd_mask_extra = CD_MASK_DYNTOPO_VERT}));
|
||||
|
||||
SCULPT_dyntopo_node_layers_add(ob->sculpt);
|
||||
|
||||
SCULPT_undo_ensure_bmlog(ob);
|
||||
|
||||
pbvh = build_pbvh_for_dynamic_topology(ob);
|
||||
}
|
||||
else {
|
||||
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
|
||||
Mesh *mesh_eval = object_eval->data;
|
||||
if (mesh_eval->runtime.subdiv_ccg != NULL) {
|
||||
pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide);
|
||||
}
|
||||
else if (ob->type == OB_MESH) {
|
||||
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
|
||||
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
|
||||
Mesh *mesh_eval = object_eval->data;
|
||||
if (mesh_eval->runtime.subdiv_ccg != NULL) {
|
||||
@@ -2206,11 +2365,20 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
|
||||
}
|
||||
else if (ob->type == OB_MESH) {
|
||||
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
|
||||
|
||||
BKE_sculptsession_check_mdyntopo(ob->sculpt, me_eval_deform->totvert);
|
||||
|
||||
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ob->sculpt->pbvh = pbvh;
|
||||
|
||||
if (pbvh) {
|
||||
SCULPT_update_flat_vcol_shading(ob, scene);
|
||||
}
|
||||
|
||||
return pbvh;
|
||||
}
|
||||
|
||||
@@ -2232,6 +2400,12 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
|
||||
return !(v3d && (v3d->shading.type > OB_SOLID));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
|
||||
/* Regular mesh only draws from PBVH without modifiers and shape keys. */
|
||||
const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID));
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
31
source/blender/blenkernel/intern/pbvh_cache_test_main.c
Normal file
31
source/blender/blenkernel/intern/pbvh_cache_test_main.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_pbvh.h"
|
||||
|
||||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
#include "pbvh_intern.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// void pbvh_bmesh_do_cache_test(void);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("argc: %d\n", argc);
|
||||
|
||||
// pbvh_bmesh_do_cache_test();
|
||||
|
||||
return 0;
|
||||
}
|
266
source/blender/blenkernel/intern/pbvh_displacement.c
Normal file
266
source/blender/blenkernel/intern/pbvh_displacement.c
Normal file
@@ -0,0 +1,266 @@
|
||||
#if 0
|
||||
# include "MEM_guardedalloc.h"
|
||||
|
||||
# include "BLI_alloca.h"
|
||||
# include "BLI_array.h"
|
||||
# include "BLI_compiler_attrs.h"
|
||||
# include "BLI_compiler_compat.h"
|
||||
# include "BLI_ghash.h"
|
||||
# include "BLI_linklist.h"
|
||||
# include "BLI_math.h"
|
||||
# include "BLI_memarena.h"
|
||||
# include "BLI_memblock.h"
|
||||
# include "BLI_mempool.h"
|
||||
# include "BLI_utildefines.h"
|
||||
|
||||
# include "BLI_hash.h"
|
||||
|
||||
# include "BKE_context.h"
|
||||
# include "BKE_global.h"
|
||||
# include "BKE_image.h"
|
||||
# include "BKE_mesh.h"
|
||||
# include "BKE_multires.h"
|
||||
# include "BKE_object.h"
|
||||
# include "BKE_pbvh.h"
|
||||
# include "BKE_scene.h"
|
||||
|
||||
# include "BLI_bitmap.h"
|
||||
# include "DNA_customdata_types.h"
|
||||
# include "DNA_image_types.h"
|
||||
# include "DNA_material_types.h"
|
||||
# include "DNA_mesh_types.h"
|
||||
# include "DNA_meshdata_types.h"
|
||||
# include "DNA_object_types.h"
|
||||
# include "DNA_scene_types.h"
|
||||
|
||||
# include "pbvh_intern.h"
|
||||
|
||||
# include "bmesh.h"
|
||||
|
||||
void *BKE_pbvh_get_tex_settings(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
|
||||
{
|
||||
return NULL; // implement me!
|
||||
}
|
||||
|
||||
void *BKE_pbvh_get_tex_data(PBVH *pbvh, PBVHNode *node, TexPointRef vdm)
|
||||
{
|
||||
return NULL; // implement me!
|
||||
}
|
||||
|
||||
typedef union TexelKey {
|
||||
struct {
|
||||
int idx; // index in image
|
||||
int co_key; // used to differentiate same texel used in different 3d points in space
|
||||
} key;
|
||||
intptr_t i;
|
||||
} TexelKey;
|
||||
|
||||
BLI_INLINE int calc_co_key(const float *co)
|
||||
{
|
||||
const int mul = 65535;
|
||||
const int mask = 65535;
|
||||
|
||||
int x = (int)co[0] + (((int)co[0] * mul) & mask);
|
||||
int y = (int)co[0] + (((int)co[0] * mul) & mask);
|
||||
int z = (int)co[0] + (((int)co[0] * mul) & mask);
|
||||
|
||||
return BLI_hash_int_3d(x, y, z);
|
||||
}
|
||||
|
||||
typedef struct TextureVDMSettings {
|
||||
ImageUser ima_user;
|
||||
ID *image;
|
||||
bool tangent_space;
|
||||
|
||||
char uv_layer[64];
|
||||
|
||||
// used by texture_vdm_get_points
|
||||
// BLI_bitmap *texel_used_map;
|
||||
GSet *texel_used_map;
|
||||
|
||||
int width, height;
|
||||
bool invalid;
|
||||
} TextureVDMSettings;
|
||||
|
||||
typedef struct TextureNodeData {
|
||||
TexPointRef *point_ids;
|
||||
float (*point_cos)[3];
|
||||
float (*point_uvs)[2];
|
||||
float **point_cos_ptrs;
|
||||
int totpoint;
|
||||
} TextureNodeData;
|
||||
|
||||
void texture_vdm_begin(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
|
||||
{
|
||||
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
|
||||
|
||||
if (!settings->image) {
|
||||
return;
|
||||
}
|
||||
|
||||
Image *image = (Image *)settings->image;
|
||||
|
||||
int w = 0, h = 0;
|
||||
BKE_image_get_size(image, &settings->ima_user, &w, &h);
|
||||
|
||||
// Image *image = settings->image.
|
||||
settings->width = w;
|
||||
settings->height = h;
|
||||
// settings->texel_used_map = BLI_BITMAP_NEW(w * h, "texel_used_map");
|
||||
settings->texel_used_map = BLI_gset_ptr_new("texel_used_map");
|
||||
}
|
||||
|
||||
void texture_vdm_build_points(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
|
||||
{
|
||||
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
|
||||
TextureNodeData *data = BKE_pbvh_get_tex_data(pbvh, node, vdm);
|
||||
|
||||
int idx;
|
||||
|
||||
if (!settings->uv_layer[0]) {
|
||||
idx = CustomData_get_layer_index(&pbvh->bm->ldata, CD_MLOOPUV);
|
||||
}
|
||||
else {
|
||||
idx = CustomData_get_named_layer_index(&pbvh->bm->ldata, CD_MLOOPUV, settings->uv_layer);
|
||||
}
|
||||
|
||||
if (idx < 0) {
|
||||
settings->invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const int cd_uv = pbvh->bm->ldata.layers[idx].offset;
|
||||
const int w = settings->width, h = settings->height;
|
||||
|
||||
float **point_cos_ptrs = NULL;
|
||||
float *uvs = NULL;
|
||||
float *cos = NULL;
|
||||
TexPointRef *ids = NULL;
|
||||
|
||||
BLI_array_declare(point_cos_ptrs);
|
||||
BLI_array_declare(uvs);
|
||||
BLI_array_declare(cos);
|
||||
BLI_array_declare(ids);
|
||||
|
||||
for (int i = 0; i < node->tribuf->tottri; i++) {
|
||||
PBVHTri *tri = node->tribuf->tris + i;
|
||||
|
||||
BMLoop *ls[3] = {(BMLoop *)tri->l[0], (BMLoop *)tri->l[1], (BMLoop *)tri->l[2]};
|
||||
float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {FLT_MIN, FLT_MIN};
|
||||
|
||||
float tricos[3][3];
|
||||
|
||||
copy_v3_v3(tricos[0], ls[0]->v->co);
|
||||
copy_v3_v3(tricos[1], ls[1]->v->co);
|
||||
copy_v3_v3(tricos[2], ls[2]->v->co);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(ls[j], cd_uv);
|
||||
minmax_v2v2_v2(min, max, luv->uv);
|
||||
}
|
||||
|
||||
int dw = (int)((max[0] - min[0]) * (float)w + 0.000001f);
|
||||
int dh = (int)((max[1] - min[1]) * (float)h + 0.000001f);
|
||||
|
||||
dw = MAX2(dw, 1);
|
||||
dh = MAX2(dh, 1);
|
||||
|
||||
float du = (max[0] - min[0]) / dw;
|
||||
float dv = (max[1] - min[1]) / dh;
|
||||
|
||||
float u = min[0], v = min[1];
|
||||
for (int y = 0; y < dh; y++, v += dv) {
|
||||
u = min[0];
|
||||
|
||||
for (int x = 0; x < dw; x++, u += du) {
|
||||
int idx = y * w + x;
|
||||
float co[3];
|
||||
|
||||
interp_barycentric_tri_v3(tricos, u, v, co);
|
||||
|
||||
TexelKey key;
|
||||
key.key.idx = idx;
|
||||
key.key.co_key = calc_co_key(co);
|
||||
|
||||
if (BLI_gset_haskey(settings->texel_used_map, (void *)key.i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BLI_gset_insert(settings->texel_used_map, (void *)key.i);
|
||||
|
||||
BLI_array_append(uvs, u);
|
||||
BLI_array_append(uvs, v);
|
||||
|
||||
BLI_array_append(cos, co[0]);
|
||||
BLI_array_append(cos, co[1]);
|
||||
BLI_array_append(cos, co[2]);
|
||||
BLI_array_append(ids, (TexPointRef)key.i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settings->invalid = false;
|
||||
MEM_SAFE_FREE(data->point_cos);
|
||||
MEM_SAFE_FREE(data->point_ids);
|
||||
MEM_SAFE_FREE(data->point_uvs);
|
||||
MEM_SAFE_FREE(data->point_cos_ptrs);
|
||||
|
||||
int totpoint = BLI_array_len(ids);
|
||||
|
||||
data->totpoint = totpoint;
|
||||
|
||||
data->point_cos_ptrs = MEM_malloc_arrayN(totpoint, sizeof(void *), "point_cos_ptrs");
|
||||
|
||||
// dumb casting trick
|
||||
union {
|
||||
float *cos;
|
||||
float (*cos3)[3];
|
||||
} castcos;
|
||||
|
||||
union {
|
||||
float *uvs;
|
||||
float (*uvs2)[2];
|
||||
} castuvs;
|
||||
|
||||
castcos.cos = cos;
|
||||
castuvs.uvs = uvs;
|
||||
|
||||
data->point_cos = castcos.cos3;
|
||||
data->point_ids = ids;
|
||||
data->point_uvs = castuvs.uvs2;
|
||||
|
||||
for (int i = 0; i < totpoint; i++) {
|
||||
data->point_cos_ptrs[i] = cos + i * 3;
|
||||
}
|
||||
}
|
||||
|
||||
void texture_vdm_get_points(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
TexLayerRef vdm,
|
||||
TexPointRef **r_ids,
|
||||
float ***r_cos,
|
||||
float ***r_nos,
|
||||
int *r_totpoint)
|
||||
{
|
||||
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
|
||||
TextureNodeData *data = BKE_pbvh_get_tex_data(pbvh, node, vdm);
|
||||
|
||||
if (r_totpoint) {
|
||||
*r_totpoint = data->totpoint;
|
||||
}
|
||||
|
||||
if (r_cos) {
|
||||
*r_cos = data->point_cos_ptrs;
|
||||
}
|
||||
|
||||
if (r_ids) {
|
||||
*r_ids = data->point_ids;
|
||||
}
|
||||
}
|
||||
|
||||
static SculptDisplacementDef texture_vdm = {
|
||||
.type = SCULPT_TEXTURE_UV,
|
||||
.settings_size = sizeof(TextureNodeData),
|
||||
.getPointsFromNode = texture_vdm_get_points,
|
||||
};
|
||||
#endif
|
@@ -16,9 +16,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
/** \file
|
||||
* \ingroup bli
|
||||
*/
|
||||
struct MDynTopoVert;
|
||||
|
||||
/* Axis-aligned bounding box */
|
||||
typedef struct {
|
||||
@@ -35,6 +43,10 @@ typedef struct {
|
||||
struct PBVHNode {
|
||||
/* Opaque handle for drawing code */
|
||||
struct GPU_PBVH_Buffers *draw_buffers;
|
||||
struct GPU_PBVH_Buffers **mat_draw_buffers; // currently only used by pbvh_bmesh
|
||||
int tot_mat_draw_buffers;
|
||||
|
||||
int id;
|
||||
|
||||
/* Voxel bounds */
|
||||
BB vb;
|
||||
@@ -43,6 +55,7 @@ struct PBVHNode {
|
||||
/* For internal nodes, the offset of the children in the PBVH
|
||||
* 'nodes' array. */
|
||||
int children_offset;
|
||||
int subtree_tottri;
|
||||
|
||||
/* Pointer into the PBVH prim_indices array and the number of
|
||||
* primitives used by this leaf node.
|
||||
@@ -86,7 +99,7 @@ struct PBVHNode {
|
||||
|
||||
/* Indicates whether this node is a leaf or not; also used for
|
||||
* marking various updates that need to be applied. */
|
||||
PBVHNodeFlags flag : 16;
|
||||
PBVHNodeFlags flag : 32;
|
||||
|
||||
/* Used for raycasting: how close bb is to the ray point. */
|
||||
float tmin;
|
||||
@@ -98,27 +111,39 @@ struct PBVHNode {
|
||||
PBVHProxyNode *proxies;
|
||||
|
||||
/* Dyntopo */
|
||||
GSet *bm_faces;
|
||||
GSet *bm_unique_verts;
|
||||
GSet *bm_other_verts;
|
||||
float (*bm_orco)[3];
|
||||
int (*bm_ortri)[3];
|
||||
int bm_tot_ortri;
|
||||
TableGSet *bm_faces;
|
||||
TableGSet *bm_unique_verts;
|
||||
TableGSet *bm_other_verts;
|
||||
|
||||
PBVHTriBuf *tribuf; // all triangles
|
||||
PBVHTriBuf *tri_buffers; // tribuffers, one per material used
|
||||
int tot_tri_buffers;
|
||||
|
||||
int updategen;
|
||||
|
||||
/* Used to store the brush color during a stroke and composite it over the original color */
|
||||
PBVHColorBufferNode color_buffer;
|
||||
#ifdef PROXY_ADVANCED
|
||||
ProxyVertArray proxyverts;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PBVH_DYNTOPO_SMOOTH_SHADING = 1,
|
||||
PBVH_FAST_DRAW = 2 // hides facesets/masks and forces smooth to save GPU bandwidth
|
||||
} PBVHFlags;
|
||||
|
||||
typedef struct PBVHBMeshLog PBVHBMeshLog;
|
||||
struct DMFlagMat;
|
||||
|
||||
struct PBVH {
|
||||
PBVHType type;
|
||||
PBVHFlags flags;
|
||||
|
||||
int idgen;
|
||||
|
||||
bool dyntopo_stop;
|
||||
|
||||
PBVHNode *nodes;
|
||||
int node_mem_count, totnode;
|
||||
|
||||
@@ -127,6 +152,7 @@ struct PBVH {
|
||||
int totvert;
|
||||
|
||||
int leaf_limit;
|
||||
int depth_limit;
|
||||
|
||||
/* Mesh data */
|
||||
const struct Mesh *mesh;
|
||||
@@ -146,7 +172,7 @@ struct PBVH {
|
||||
CCGKey gridkey;
|
||||
CCGElem **grids;
|
||||
void **gridfaces;
|
||||
const DMFlagMat *grid_flag_mats;
|
||||
const struct DMFlagMat *grid_flag_mats;
|
||||
int totgrid;
|
||||
BLI_bitmap **grid_hidden;
|
||||
|
||||
@@ -168,14 +194,31 @@ struct PBVH {
|
||||
BMesh *bm;
|
||||
float bm_max_edge_len;
|
||||
float bm_min_edge_len;
|
||||
float bm_detail_range;
|
||||
|
||||
int cd_dyn_vert;
|
||||
int cd_vert_node_offset;
|
||||
int cd_face_node_offset;
|
||||
int cd_vert_mask_offset;
|
||||
int cd_vcol_offset;
|
||||
int cd_faceset_offset;
|
||||
int cd_face_area;
|
||||
|
||||
float planes[6][4];
|
||||
int num_planes;
|
||||
|
||||
int symmetry;
|
||||
int boundary_symmetry;
|
||||
|
||||
struct BMLog *bm_log;
|
||||
struct SubdivCCG *subdiv_ccg;
|
||||
|
||||
bool flat_vcol_shading;
|
||||
bool need_full_render; // used by pbvh drawing for PBVH_BMESH
|
||||
|
||||
int balance_counter;
|
||||
int stroke_id; // used to keep origdata up to date in PBVH_BMESH
|
||||
struct MDynTopoVert *mdyntopo_verts;
|
||||
};
|
||||
|
||||
/* pbvh.c */
|
||||
@@ -184,6 +227,9 @@ void BB_expand(BB *bb, const float co[3]);
|
||||
void BB_expand_with_bb(BB *bb, BB *bb2);
|
||||
void BBC_update_centroid(BBC *bbc);
|
||||
int BB_widest_axis(const BB *bb);
|
||||
void BB_intersect(BB *r_out, BB *a, BB *b);
|
||||
float BB_volume(const BB *bb);
|
||||
|
||||
void pbvh_grow_nodes(PBVH *bvh, int totnode);
|
||||
bool ray_face_intersection_quad(const float ray_start[3],
|
||||
struct IsectRayPrecalc *isect_precalc,
|
||||
@@ -218,19 +264,85 @@ bool ray_face_nearest_tri(const float ray_start[3],
|
||||
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
|
||||
|
||||
/* pbvh_bmesh.c */
|
||||
bool pbvh_bmesh_node_raycast(PBVHNode *node,
|
||||
bool pbvh_bmesh_node_raycast(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
const float ray_start[3],
|
||||
const float ray_normal[3],
|
||||
struct IsectRayPrecalc *isect_precalc,
|
||||
float *dist,
|
||||
bool use_original,
|
||||
int *r_active_vertex_index,
|
||||
float *r_face_normal);
|
||||
bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
|
||||
struct SculptVertRef *r_active_vertex_index,
|
||||
struct SculptFaceRef *r_active_face_index,
|
||||
float *r_face_normal,
|
||||
int stroke_id);
|
||||
|
||||
bool pbvh_bmesh_node_nearest_to_ray(PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
const float ray_start[3],
|
||||
const float ray_normal[3],
|
||||
float *depth,
|
||||
float *dist_sq,
|
||||
bool use_original);
|
||||
bool use_original,
|
||||
int stroke_id);
|
||||
|
||||
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
|
||||
|
||||
void pbvh_free_all_draw_buffers(PBVHNode *node);
|
||||
void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node);
|
||||
|
||||
BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *pbvh, const BMVert *key)
|
||||
{
|
||||
const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh->cd_vert_node_offset);
|
||||
BLI_assert(node_index != DYNTOPO_NODE_NONE);
|
||||
BLI_assert(node_index < pbvh->totnode);
|
||||
return node_index;
|
||||
}
|
||||
|
||||
BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *pbvh, const BMFace *key)
|
||||
{
|
||||
const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh->cd_face_node_offset);
|
||||
BLI_assert(node_index != DYNTOPO_NODE_NONE);
|
||||
BLI_assert(node_index < pbvh->totnode);
|
||||
return node_index;
|
||||
}
|
||||
|
||||
BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *pbvh, const BMVert *key)
|
||||
{
|
||||
int ni = pbvh_bmesh_node_index_from_vert(pbvh, key);
|
||||
|
||||
return ni >= 0 ? pbvh->nodes + ni : NULL;
|
||||
// return &pbvh->nodes[pbvh_bmesh_node_index_from_vert(pbvh, key)];
|
||||
}
|
||||
|
||||
BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *pbvh, const BMFace *key)
|
||||
{
|
||||
int ni = pbvh_bmesh_node_index_from_face(pbvh, key);
|
||||
|
||||
return ni >= 0 ? pbvh->nodes + ni : NULL;
|
||||
// return &pbvh->nodes[pbvh_bmesh_node_index_from_face(pbvh, key)];
|
||||
}
|
||||
bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index);
|
||||
void pbvh_bmesh_check_nodes(PBVH *pbvh);
|
||||
void bke_pbvh_insert_face_finalize(PBVH *pbvh, BMFace *f, const int ni);
|
||||
void bke_pbvh_insert_face(PBVH *pbvh, struct BMFace *f);
|
||||
void bke_pbvh_update_vert_boundary(int cd_dyn_vert,
|
||||
int cd_faceset_offset,
|
||||
BMVert *v,
|
||||
int bound_symmetry);
|
||||
|
||||
BLI_INLINE bool pbvh_check_vert_boundary(PBVH *pbvh, struct BMVert *v)
|
||||
{
|
||||
MDynTopoVert *mv = (MDynTopoVert *)BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_dyn_vert);
|
||||
|
||||
if (mv->flag & DYNVERT_NEED_BOUNDARY) {
|
||||
bke_pbvh_update_vert_boundary(
|
||||
pbvh->cd_dyn_vert, pbvh->cd_faceset_offset, v, pbvh->boundary_symmetry);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void pbvh_bmesh_check_other_verts(PBVHNode *node);
|
||||
|
||||
//#define DEFRAGMENT_MEMORY
|
||||
|
@@ -69,6 +69,7 @@
|
||||
#include "BKE_anim_data.h"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_brush_engine.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_colortools.h"
|
||||
@@ -849,6 +850,11 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
|
||||
}
|
||||
if (tos->sculpt) {
|
||||
BLO_write_struct(writer, Sculpt, tos->sculpt);
|
||||
|
||||
if (tos->sculpt->channels) {
|
||||
BKE_brush_channelset_write(writer, tos->sculpt->channels);
|
||||
}
|
||||
|
||||
BKE_paint_blend_write(writer, &tos->sculpt->paint);
|
||||
}
|
||||
if (tos->uvsculpt) {
|
||||
@@ -1050,6 +1056,11 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
sce->toolsettings->particle.object = NULL;
|
||||
sce->toolsettings->gp_sculpt.paintcursor = NULL;
|
||||
|
||||
if (sce->toolsettings->sculpt && sce->toolsettings->sculpt->channels) {
|
||||
BLO_read_data_address(reader, &sce->toolsettings->sculpt->channels);
|
||||
BKE_brush_channelset_read(reader, sce->toolsettings->sculpt->channels);
|
||||
}
|
||||
|
||||
/* relink grease pencil interpolation curves */
|
||||
BLO_read_data_address(reader, &sce->toolsettings->gp_interpolate.custom_ipo);
|
||||
if (sce->toolsettings->gp_interpolate.custom_ipo) {
|
||||
@@ -2393,6 +2404,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_
|
||||
if (check_rendered_viewport_visible(bmain)) {
|
||||
BMesh *bm = mesh->edit_mesh->bm;
|
||||
BM_mesh_bm_to_me(bmain,
|
||||
NULL,
|
||||
bm,
|
||||
mesh,
|
||||
(&(struct BMeshToMeshParams){
|
||||
|
@@ -360,6 +360,7 @@ static void eval_displacement(SubdivDisplacement *displacement,
|
||||
BKE_multires_construct_tangent_matrix(tangent_matrix, dPdu, dPdv, corner_of_quad);
|
||||
mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
|
||||
/* For the boundary points of grid average two (or all) neighbor grids. */
|
||||
|
||||
const int corner = displacement_get_face_corner(data, ptex_face_index, u, v);
|
||||
average_displacement(displacement, average_with, ptex_face_index, corner, grid_u, grid_v, r_D);
|
||||
}
|
||||
|
@@ -1866,11 +1866,14 @@ static const MeshElemMap *ccgDM_getPolyMap(Object *ob, DerivedMesh *dm)
|
||||
|
||||
BKE_mesh_vert_poly_map_create(&ccgdm->pmap,
|
||||
&ccgdm->pmap_mem,
|
||||
me->mvert,
|
||||
me->medge,
|
||||
me->mpoly,
|
||||
me->mloop,
|
||||
me->totvert,
|
||||
me->totpoly,
|
||||
me->totloop);
|
||||
me->totloop,
|
||||
false);
|
||||
}
|
||||
|
||||
return ccgdm->pmap;
|
||||
|
@@ -21,7 +21,7 @@
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)) && !defined(_MSC_VER)
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
# include "sanitizer/asan_interface.h"
|
||||
#else
|
||||
/* Ensure return value is used. Just using UNUSED_VARS results in a warning. */
|
||||
@@ -40,3 +40,59 @@
|
||||
* Mark a region of memory as usable again.
|
||||
*/
|
||||
#define BLI_asan_unpoison(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
|
||||
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
# include "MEM_guardedalloc.h"
|
||||
|
||||
static void *BLI_asan_safe_malloc(size_t size, const char *tag)
|
||||
{
|
||||
// align size at 16 bytes
|
||||
size += 15 - (size & 15);
|
||||
|
||||
// add safe padding
|
||||
size += 32;
|
||||
|
||||
void *ret = MEM_mallocN(size, tag);
|
||||
|
||||
int *iptr = (int *)ret;
|
||||
*iptr = (int)size;
|
||||
|
||||
char *ptr = (char *)ret;
|
||||
|
||||
ptr[4] = 't';
|
||||
ptr[5] = 'a';
|
||||
ptr[6] = 'g';
|
||||
ptr[7] = '1';
|
||||
|
||||
BLI_asan_poison(ptr, 16);
|
||||
BLI_asan_poison(ptr + size - 16, 16);
|
||||
|
||||
ret = (void *)(ptr + 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void BLI_asan_safe_free(void *mem)
|
||||
{
|
||||
if (!mem) {
|
||||
return;
|
||||
}
|
||||
|
||||
mem = (void *)(((char *)mem) - 16);
|
||||
|
||||
BLI_asan_unpoison(mem, 16);
|
||||
int *iptr = (int *)mem;
|
||||
volatile char *ptr = (char *)mem;
|
||||
|
||||
if (ptr[4] != 't' || ptr[5] != 'a' || ptr[6] != 'g' || ptr[7] != '1') {
|
||||
BLI_asan_poison(mem, 16);
|
||||
*ptr = 1; // deliberately trigger asan fault
|
||||
}
|
||||
|
||||
BLI_asan_unpoison(ptr + iptr[0] - 16, 16);
|
||||
MEM_freeN((void *)ptr);
|
||||
}
|
||||
#else
|
||||
# define BLI_asan_safe_malloc(size, tag) MEM_mallocN(size, tag)
|
||||
# define BLI_asan_safe_free(mem) MEM_SAFE_FREE(mem)
|
||||
#endif
|
||||
|
@@ -33,6 +33,12 @@
|
||||
/* hint to mark function arguments expected to be non-null
|
||||
* if no arguments are given to the macro, all of pointer
|
||||
* arguments would be expected to be non-null
|
||||
*
|
||||
* ONE-INDEXED!
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* void func(void *a, void *b, void *b) ATTR_NONNULL(1, 2, 3)
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
# define ATTR_NONNULL(args...) __attribute__((nonnull(args)))
|
||||
@@ -99,6 +105,17 @@
|
||||
# define ATTR_ALIGN(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
/* Disable optimization for a function (for debugging use only!)*/
|
||||
#ifdef __clang__
|
||||
# define ATTR_NO_OPT __attribute__((optnone))
|
||||
#elif defined(__MSC_VER)
|
||||
# define ATTR_NO_OPT __pragma(optimize("", off))
|
||||
#elif defined(__GNUC__)
|
||||
# define ATTR_NO_OPT __attribute__((optimize("O0")))
|
||||
#else
|
||||
# define ATTR_NO_OPT
|
||||
#endif
|
||||
|
||||
/* Alignment directive */
|
||||
#ifdef _WIN64
|
||||
# define ALIGN_STRUCT __declspec(align(64))
|
||||
|
@@ -188,6 +188,53 @@ BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi)
|
||||
|
||||
typedef struct GSet GSet;
|
||||
|
||||
struct SmallHash;
|
||||
|
||||
#include "BLI_smallhash.h"
|
||||
|
||||
typedef struct TableGSet {
|
||||
struct SmallHash ptr_to_idx;
|
||||
void **elems;
|
||||
int size, length;
|
||||
int cur;
|
||||
} TableGSet;
|
||||
|
||||
TableGSet *BLI_table_gset_new(const char *info);
|
||||
TableGSet *BLI_table_gset_new_ex(const char *info, int size);
|
||||
void BLI_table_gset_free(TableGSet *ts, GHashKeyFreeFP freefp);
|
||||
void BLI_table_gset_insert(TableGSet *ts, void *elem);
|
||||
bool BLI_table_gset_add(TableGSet *ts, void *elem);
|
||||
void BLI_table_gset_remove(TableGSet *ts, void *elem, GHashKeyFreeFP freefp);
|
||||
bool BLI_table_gset_haskey(TableGSet *ts, void *elem);
|
||||
|
||||
int BLI_table_gset_len(TableGSet *ts);
|
||||
|
||||
#define TGSET_ITER(v, ts) \
|
||||
{ \
|
||||
int _i1; \
|
||||
for (_i1 = 0; _i1 < (ts)->cur; _i1++) { \
|
||||
if (!(ts)->elems[_i1]) \
|
||||
continue; \
|
||||
v = (ts)->elems[_i1];
|
||||
|
||||
#define TGSET_ITER_END \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TGSET_ITER_INDEX(v, ts, index) \
|
||||
{ \
|
||||
int _i1; \
|
||||
index = -1; \
|
||||
for (_i1 = 0; _i1 < (ts)->cur; _i1++) { \
|
||||
if (!(ts)->elems[_i1]) \
|
||||
continue; \
|
||||
v = (ts)->elems[_i1]; \
|
||||
index++;
|
||||
|
||||
#define TGSET_ITER_INDEX_END \
|
||||
} \
|
||||
}
|
||||
|
||||
typedef GHashHashFP GSetHashFP;
|
||||
typedef GHashCmpFP GSetCmpFP;
|
||||
typedef GHashKeyFreeFP GSetKeyFreeFP;
|
||||
|
@@ -52,7 +52,7 @@
|
||||
#define BLI_LINKSTACK_SIZE(var) BLI_mempool_len(var##_pool_)
|
||||
|
||||
/* check for typeof() */
|
||||
#ifdef __GNUC__
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define BLI_LINKSTACK_PUSH(var, ptr) \
|
||||
(CHECK_TYPE_INLINE(ptr, typeof(var##_type_)), \
|
||||
BLI_linklist_prepend_pool(&(var), ptr, var##_pool_))
|
||||
|
@@ -87,11 +87,35 @@ enum {
|
||||
* order of allocation when no chunks have been freed.
|
||||
*/
|
||||
BLI_MEMPOOL_ALLOW_ITER = (1 << 0),
|
||||
|
||||
/* allow random access, implies BLI_MEMPOOL_ALLOW_ITER since we
|
||||
need the freewords to detect free state of elements*/
|
||||
BLI_MEMPOOL_RANDOM_ACCESS = (1 << 1) | (1 << 0)
|
||||
};
|
||||
|
||||
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL();
|
||||
void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
/*
|
||||
This preallocates a mempool suitable for threading. totelem elements are preallocated
|
||||
in chunks of size pchunk, and returned in r_chunks.
|
||||
*/
|
||||
|
||||
BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
|
||||
int totelem,
|
||||
const int pchunk,
|
||||
void ***r_chunks,
|
||||
int *r_totchunk,
|
||||
int *r_esize,
|
||||
int flag);
|
||||
|
||||
// memory coherence stuff
|
||||
int BLI_mempool_find_elems_fuzzy(
|
||||
BLI_mempool *pool, int idx, int range, void **r_elems, int r_elems_size);
|
||||
|
||||
int BLI_mempool_get_size(BLI_mempool *pool);
|
||||
int BLI_mempool_find_real_index(BLI_mempool *pool, void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -39,11 +39,13 @@ typedef struct {
|
||||
#define SMSTACKSIZE 131
|
||||
typedef struct SmallHash {
|
||||
unsigned int nbuckets;
|
||||
unsigned int nentries;
|
||||
unsigned int nentries, nfreecells;
|
||||
unsigned int cursize;
|
||||
|
||||
SmallHashEntry *buckets;
|
||||
SmallHashEntry buckets_stack[SMSTACKSIZE];
|
||||
|
||||
bool using_stack;
|
||||
} SmallHash;
|
||||
|
||||
typedef struct {
|
||||
@@ -57,22 +59,25 @@ void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1);
|
||||
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
|
||||
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
|
||||
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
|
||||
void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
|
||||
void *BLI_smallhash_lookup(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
void **BLI_smallhash_lookup_p(SmallHash *sh, uintptr_t key)
|
||||
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key)
|
||||
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
|
||||
int BLI_smallhash_len(const SmallHash *sh) ATTR_NONNULL(1);
|
||||
bool BLI_smallhash_haskey(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
|
||||
int BLI_smallhash_len(SmallHash *sh) ATTR_NONNULL(1);
|
||||
void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
|
||||
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key)
|
||||
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
|
||||
void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
|
||||
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
|
||||
void **BLI_smallhash_iternew_p(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
|
||||
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
/* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */
|
||||
|
||||
void BLI_smallhash_clear(SmallHash *sh, uintptr_t key);
|
||||
bool BLI_smallhash_ensure_p(SmallHash *sh, uintptr_t key, void ***item);
|
||||
bool BLI_smallhash_remove_p(SmallHash *sh, uintptr_t key, void **val);
|
||||
|
||||
#ifdef DEBUG
|
||||
double BLI_smallhash_calc_quality(SmallHash *sh);
|
||||
#endif
|
||||
|
@@ -45,10 +45,22 @@
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(error : 4018) /* signed/unsigned mismatch */
|
||||
# pragma warning(error : 4244) /* conversion from 'type1' to 'type2', possible loss of data */
|
||||
# pragma warning(error : 4245) /* conversion from 'int' to 'unsigned int' */
|
||||
# pragma warning(error : 4267) /* conversion from 'size_t' to 'type', possible loss of data */
|
||||
# pragma warning(error : 4305) /* truncation from 'type1' to 'type2' */
|
||||
# pragma warning(error : 4389) /* signed/unsigned mismatch */
|
||||
/* While regular clang defines __GNUC__ and is handled by the code above, clang-cl does not and
|
||||
* needs to be handled separately. */
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic error "-Wsign-conversion"
|
||||
# pragma clang diagnostic error "-Wsign-compare"
|
||||
# pragma clang diagnostic error "-Wimplicit-float-conversion"
|
||||
# pragma clang diagnostic error "-Wimplicit-int-conversion"
|
||||
# pragma clang diagnostic error "-Wimplicit-int"
|
||||
# pragma clang diagnostic error "-Wshadow"
|
||||
/* Normal MSVC */
|
||||
# else
|
||||
# pragma warning(error : 4018) /* signed/unsigned mismatch */
|
||||
# pragma warning(error : 4244) /* conversion from 'type1' to 'type2', possible loss of data */
|
||||
# pragma warning(error : 4245) /* conversion from 'int' to 'unsigned int' */
|
||||
# pragma warning(error : 4267) /* conversion from 'size_t' to 'type', possible loss of data */
|
||||
# pragma warning(error : 4305) /* truncation from 'type1' to 'type2' */
|
||||
# pragma warning(error : 4389) /* signed/unsigned mismatch */
|
||||
# endif
|
||||
#endif
|
||||
|
@@ -153,6 +153,7 @@ set(SRC
|
||||
intern/voxel.c
|
||||
intern/winstuff.c
|
||||
intern/winstuff_dir.c
|
||||
intern/BLI_table_gset.c
|
||||
|
||||
# Private headers.
|
||||
intern/BLI_mempool_private.h
|
||||
|
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_asan.h"
|
||||
#include "BLI_mempool.h" /* own include */
|
||||
#include "BLI_mempool_private.h" /* own include */
|
||||
|
||||
@@ -47,6 +48,12 @@
|
||||
# include "valgrind/memcheck.h"
|
||||
#endif
|
||||
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
# define POISON_REDZONE_SIZE 32
|
||||
#else
|
||||
# define POISON_REDZONE_SIZE 0
|
||||
#endif
|
||||
|
||||
/* NOTE: copied from BLO_blend_defs.h, don't use here because we're in BLI. */
|
||||
#ifdef __BIG_ENDIAN__
|
||||
/* Big Endian */
|
||||
@@ -117,6 +124,12 @@ struct BLI_mempool {
|
||||
* this is needed for iteration so we can loop over chunks in the order added. */
|
||||
BLI_mempool_chunk *chunk_tail;
|
||||
|
||||
/* only used if BLI_MEMPOOL_RANDOM_ACCESS is true*/
|
||||
BLI_mempool_chunk **chunktable;
|
||||
|
||||
/* only used if BLI_MEMPOOL_RANDOM_ACCESS is true*/
|
||||
int totchunk;
|
||||
|
||||
/** Element size in bytes. */
|
||||
uint esize;
|
||||
/** Chunk size in bytes. */
|
||||
@@ -161,6 +174,33 @@ static uint power_of_2_max_u(uint x)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mempool_update_chunktable(BLI_mempool *pool)
|
||||
{
|
||||
if (!(pool->flag & BLI_MEMPOOL_RANDOM_ACCESS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pool->totchunk = 0;
|
||||
BLI_mempool_chunk *chunk = pool->chunks;
|
||||
|
||||
while (chunk) {
|
||||
pool->totchunk++;
|
||||
chunk = chunk->next;
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(pool->chunktable);
|
||||
pool->chunktable = (BLI_mempool_chunk **)MEM_mallocN(
|
||||
sizeof(pool->chunktable) * (size_t)pool->totchunk, "mempool chunktable");
|
||||
|
||||
int i = 0;
|
||||
chunk = pool->chunks;
|
||||
|
||||
while (chunk) {
|
||||
pool->chunktable[i++] = chunk;
|
||||
chunk = chunk->next;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE BLI_mempool_chunk *mempool_chunk_find(BLI_mempool_chunk *head, uint index)
|
||||
{
|
||||
while (index-- && head) {
|
||||
@@ -202,6 +242,26 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
|
||||
BLI_freenode *curnode = CHUNK_DATA(mpchunk);
|
||||
uint j;
|
||||
|
||||
if (pool->flag & BLI_MEMPOOL_RANDOM_ACCESS) {
|
||||
if (!pool->chunktable ||
|
||||
MEM_allocN_len(pool->chunktable) / sizeof(void *) <= (size_t)pool->totchunk) {
|
||||
void *old = pool->chunktable;
|
||||
|
||||
int size = (int)pool->totchunk + 2;
|
||||
size += size >> 1;
|
||||
|
||||
pool->chunktable = MEM_mallocN(sizeof(void *) * (size_t)size, "mempool chunktable");
|
||||
|
||||
if (old) {
|
||||
memcpy(pool->chunktable, old, sizeof(void *) * (size_t)pool->totchunk);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(old);
|
||||
}
|
||||
|
||||
pool->chunktable[pool->totchunk++] = mpchunk;
|
||||
}
|
||||
|
||||
/* append */
|
||||
if (pool->chunk_tail) {
|
||||
pool->chunk_tail->next = mpchunk;
|
||||
@@ -222,22 +282,42 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
|
||||
j = pool->pchunk;
|
||||
if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) {
|
||||
while (j--) {
|
||||
curnode->next = NODE_STEP_NEXT(curnode);
|
||||
BLI_freenode *next;
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
|
||||
curnode->next = next = NODE_STEP_NEXT(curnode);
|
||||
curnode->freeword = FREEWORD;
|
||||
curnode = curnode->next;
|
||||
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
curnode = next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (j--) {
|
||||
curnode->next = NODE_STEP_NEXT(curnode);
|
||||
curnode = curnode->next;
|
||||
BLI_freenode *next;
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
curnode->next = next = NODE_STEP_NEXT(curnode);
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
curnode = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* terminate the list (rewind one)
|
||||
* will be overwritten if 'curnode' gets passed in again as 'last_tail' */
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_freenode *prev = NODE_STEP_PREV(curnode);
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
curnode = NODE_STEP_PREV(curnode);
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
curnode->next = NULL;
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
#ifdef USE_TOTALLOC
|
||||
pool->totalloc += pool->pchunk;
|
||||
@@ -245,24 +325,128 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
|
||||
|
||||
/* final pointer in the previously allocated chunk is wrong */
|
||||
if (last_tail) {
|
||||
BLI_asan_unpoison(last_tail, pool->esize);
|
||||
last_tail->next = CHUNK_DATA(mpchunk);
|
||||
BLI_asan_poison(last_tail, pool->esize);
|
||||
}
|
||||
|
||||
return curnode;
|
||||
}
|
||||
|
||||
static void mempool_chunk_free(BLI_mempool_chunk *mpchunk)
|
||||
/*
|
||||
This preallocates a mempool suitable for threading. totelem elements are preallocated
|
||||
in chunks of size pchunk, and returned in r_chunks. The idea is to pass these
|
||||
to tasks.
|
||||
*/
|
||||
|
||||
BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
|
||||
int totelem,
|
||||
const int pchunk,
|
||||
void ***r_chunks,
|
||||
int *r_totchunk,
|
||||
int *r_esize,
|
||||
int flag)
|
||||
{
|
||||
BLI_mempool *pool = BLI_mempool_create(esize, 0, (uint)pchunk, (uint)flag);
|
||||
|
||||
// override pchunk, may not be a power of 2
|
||||
pool->pchunk = (uint)pchunk;
|
||||
pool->csize = (uint)pchunk * pool->esize;
|
||||
|
||||
if (totelem % pchunk == 0) {
|
||||
pool->maxchunks = (uint)totelem / (uint)pchunk;
|
||||
}
|
||||
else {
|
||||
pool->maxchunks = (uint)totelem / (uint)pchunk + 1;
|
||||
}
|
||||
|
||||
if (totelem) {
|
||||
BLI_freenode *last_tail = NULL;
|
||||
|
||||
/* Allocate the actual chunks. */
|
||||
for (uint i = 0; i < pool->maxchunks; i++) {
|
||||
BLI_mempool_chunk *mpchunk = mempool_chunk_alloc(pool);
|
||||
last_tail = mempool_chunk_add(pool, mpchunk, last_tail);
|
||||
}
|
||||
}
|
||||
|
||||
void **chunks = MEM_callocN(sizeof(void *) * pool->maxchunks,
|
||||
"BLI_mempool_create_for_tasks r_chunks");
|
||||
|
||||
unsigned int totalloc = 0;
|
||||
*r_totchunk = 0;
|
||||
|
||||
BLI_mempool_chunk *chunk = pool->chunks, *lastchunk = NULL;
|
||||
|
||||
while (chunk) {
|
||||
lastchunk = chunk;
|
||||
totalloc += pool->pchunk;
|
||||
chunk = chunk->next;
|
||||
}
|
||||
|
||||
pool->totused = totalloc;
|
||||
pool->free = NULL;
|
||||
|
||||
int i = (int)pool->pchunk - 1;
|
||||
|
||||
while (lastchunk && totalloc > (uint)totelem) {
|
||||
if (i < 0) {
|
||||
BLI_mempool_chunk *lastchunk2 = NULL;
|
||||
|
||||
for (chunk = pool->chunks; chunk; chunk = chunk->next) {
|
||||
if (chunk == lastchunk) {
|
||||
lastchunk = lastchunk2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lastchunk) {
|
||||
break;
|
||||
}
|
||||
|
||||
i = (int)pool->pchunk - 1;
|
||||
}
|
||||
|
||||
char *elem = CHUNK_DATA(lastchunk);
|
||||
elem += pool->esize * (unsigned int)i;
|
||||
|
||||
BLI_mempool_free(pool, elem);
|
||||
|
||||
totalloc--;
|
||||
i--;
|
||||
}
|
||||
|
||||
int ci = 0;
|
||||
|
||||
chunk = pool->chunks;
|
||||
while (chunk && chunk != lastchunk) {
|
||||
chunks[ci++] = CHUNK_DATA(chunk);
|
||||
chunk = chunk->next;
|
||||
}
|
||||
|
||||
if (lastchunk && i >= 0) {
|
||||
chunks[ci++] = CHUNK_DATA(lastchunk);
|
||||
}
|
||||
|
||||
*r_totchunk = ci;
|
||||
*r_chunks = (void **)chunks;
|
||||
*r_esize = (int)pool->esize;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
static void mempool_chunk_free(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
|
||||
{
|
||||
BLI_asan_unpoison(mpchunk, sizeof(BLI_mempool_chunk) + pool->esize * pool->csize);
|
||||
MEM_freeN(mpchunk);
|
||||
}
|
||||
|
||||
static void mempool_chunk_free_all(BLI_mempool_chunk *mpchunk)
|
||||
static void mempool_chunk_free_all(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
|
||||
{
|
||||
BLI_mempool_chunk *mpchunk_next;
|
||||
|
||||
for (; mpchunk; mpchunk = mpchunk_next) {
|
||||
mpchunk_next = mpchunk->next;
|
||||
mempool_chunk_free(mpchunk);
|
||||
mempool_chunk_free(mpchunk, pool);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,6 +459,9 @@ BLI_mempool *BLI_mempool_create(uint esize, uint totelem, uint pchunk, uint flag
|
||||
/* allocate the pool structure */
|
||||
pool = MEM_mallocN(sizeof(BLI_mempool), "memory pool");
|
||||
|
||||
pool->totchunk = 0;
|
||||
pool->chunktable = NULL;
|
||||
|
||||
/* set the elem size */
|
||||
if (esize < (int)MEMPOOL_ELEM_SIZE_MIN) {
|
||||
esize = (int)MEMPOOL_ELEM_SIZE_MIN;
|
||||
@@ -284,6 +471,8 @@ BLI_mempool *BLI_mempool_create(uint esize, uint totelem, uint pchunk, uint flag
|
||||
esize = MAX2(esize, (uint)sizeof(BLI_freenode));
|
||||
}
|
||||
|
||||
esize += POISON_REDZONE_SIZE;
|
||||
|
||||
maxchunks = mempool_maxchunks(totelem, pchunk);
|
||||
|
||||
pool->chunks = NULL;
|
||||
@@ -344,6 +533,8 @@ void *BLI_mempool_alloc(BLI_mempool *pool)
|
||||
|
||||
free_pop = pool->free;
|
||||
|
||||
BLI_asan_unpoison(free_pop, pool->esize - POISON_REDZONE_SIZE);
|
||||
|
||||
BLI_assert(pool->chunk_tail->next == NULL);
|
||||
|
||||
if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) {
|
||||
@@ -363,10 +554,88 @@ void *BLI_mempool_alloc(BLI_mempool *pool)
|
||||
void *BLI_mempool_calloc(BLI_mempool *pool)
|
||||
{
|
||||
void *retval = BLI_mempool_alloc(pool);
|
||||
memset(retval, 0, (size_t)pool->esize);
|
||||
memset(retval, 0, (size_t)pool->esize - POISON_REDZONE_SIZE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int BLI_mempool_find_real_index(BLI_mempool *pool, void *ptr)
|
||||
{
|
||||
BLI_mempool_chunk *chunk = pool->chunks;
|
||||
uintptr_t uptr = ptr;
|
||||
uintptr_t cptr;
|
||||
int chunki = 0;
|
||||
|
||||
while (chunk) {
|
||||
cptr = (uintptr_t)chunk;
|
||||
|
||||
if (uptr >= cptr && uptr < cptr + pool->csize) {
|
||||
break;
|
||||
}
|
||||
|
||||
chunk = chunk->next;
|
||||
chunki++;
|
||||
}
|
||||
|
||||
if (!chunk) {
|
||||
return -1; // failed
|
||||
}
|
||||
|
||||
return chunki * (int)pool->pchunk + ((int)(uptr - cptr)) / (int)pool->esize;
|
||||
}
|
||||
|
||||
/*finds an element in pool that's roughly at idx, idx*/
|
||||
int BLI_mempool_find_elems_fuzzy(
|
||||
BLI_mempool *pool, int idx, int range, void **r_elems, int r_elems_size)
|
||||
{
|
||||
int istart = idx - range, iend = idx + range;
|
||||
istart = MAX2(istart, 0);
|
||||
|
||||
int totelem = 0;
|
||||
|
||||
for (int i = istart; i < iend; i++) {
|
||||
int chunki = i / (int)pool->pchunk;
|
||||
if (chunki >= (int)pool->totchunk) {
|
||||
break;
|
||||
}
|
||||
|
||||
int idx2 = i % (int)pool->pchunk;
|
||||
|
||||
BLI_mempool_chunk *chunk = pool->chunktable[chunki];
|
||||
char *data = (char *)CHUNK_DATA(chunk);
|
||||
void *ptr = data + idx2 * (int)pool->esize;
|
||||
|
||||
BLI_asan_unpoison(ptr, pool->esize);
|
||||
|
||||
BLI_freenode *fnode = (BLI_freenode *)ptr;
|
||||
if (fnode->freeword == FREEWORD) {
|
||||
BLI_asan_poison(ptr, pool->esize);
|
||||
continue;
|
||||
}
|
||||
|
||||
r_elems[totelem++] = ptr;
|
||||
|
||||
if (totelem == r_elems_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return totelem;
|
||||
}
|
||||
|
||||
int BLI_mempool_get_size(BLI_mempool *pool)
|
||||
{
|
||||
BLI_mempool_chunk *chunk = pool->chunks;
|
||||
int ret = 0;
|
||||
|
||||
while (chunk) {
|
||||
chunk = chunk->next;
|
||||
|
||||
ret += (int)pool->pchunk;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an element from the mempool.
|
||||
*
|
||||
@@ -393,7 +662,7 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
|
||||
|
||||
/* Enable for debugging. */
|
||||
if (UNLIKELY(mempool_debug_memset)) {
|
||||
memset(addr, 255, pool->esize);
|
||||
memset(addr, 255, pool->esize - POISON_REDZONE_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -408,6 +677,8 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
|
||||
newhead->next = pool->free;
|
||||
pool->free = newhead;
|
||||
|
||||
BLI_asan_poison(newhead, pool->esize);
|
||||
|
||||
pool->totused--;
|
||||
|
||||
#ifdef WITH_MEM_VALGRIND
|
||||
@@ -422,10 +693,12 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
|
||||
BLI_mempool_chunk *first;
|
||||
|
||||
first = pool->chunks;
|
||||
mempool_chunk_free_all(first->next);
|
||||
mempool_chunk_free_all(first->next, pool);
|
||||
first->next = NULL;
|
||||
pool->chunk_tail = first;
|
||||
|
||||
mempool_update_chunktable(pool);
|
||||
|
||||
#ifdef USE_TOTALLOC
|
||||
pool->totalloc = pool->pchunk;
|
||||
#endif
|
||||
@@ -440,11 +713,21 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
|
||||
|
||||
j = pool->pchunk;
|
||||
while (j--) {
|
||||
curnode->next = NODE_STEP_NEXT(curnode);
|
||||
curnode = curnode->next;
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_freenode *next = curnode->next = NODE_STEP_NEXT(curnode);
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
curnode = next;
|
||||
}
|
||||
curnode = NODE_STEP_PREV(curnode);
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_freenode *prev = NODE_STEP_PREV(curnode);
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
curnode = prev;
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
curnode->next = NULL; /* terminate the list */
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
#ifdef WITH_MEM_VALGRIND
|
||||
VALGRIND_MEMPOOL_FREE(pool, CHUNK_DATA(first));
|
||||
@@ -510,7 +793,7 @@ void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
|
||||
*/
|
||||
void BLI_mempool_as_array(BLI_mempool *pool, void *data)
|
||||
{
|
||||
const uint esize = pool->esize;
|
||||
const uint esize = pool->esize - (uint)POISON_REDZONE_SIZE;
|
||||
BLI_mempool_iter iter;
|
||||
char *elem, *p = data;
|
||||
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
|
||||
@@ -638,12 +921,16 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
intptr_t freeword = 0;
|
||||
|
||||
const uint esize = iter->pool->esize;
|
||||
BLI_freenode *curnode = POINTER_OFFSET(CHUNK_DATA(iter->curchunk), (esize * iter->curindex));
|
||||
BLI_freenode *ret;
|
||||
do {
|
||||
ret = curnode;
|
||||
|
||||
BLI_asan_unpoison(ret, iter->pool->esize - POISON_REDZONE_SIZE);
|
||||
|
||||
if (++iter->curindex != iter->pool->pchunk) {
|
||||
curnode = POINTER_OFFSET(curnode, esize);
|
||||
}
|
||||
@@ -651,7 +938,13 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
|
||||
iter->curindex = 0;
|
||||
iter->curchunk = iter->curchunk->next;
|
||||
if (UNLIKELY(iter->curchunk == NULL)) {
|
||||
return (ret->freeword == FREEWORD) ? NULL : ret;
|
||||
BLI_asan_unpoison(ret, iter->pool->esize - POISON_REDZONE_SIZE);
|
||||
void *ret2 = (ret->freeword == FREEWORD) ? NULL : ret;
|
||||
|
||||
if (ret->freeword == FREEWORD) {
|
||||
BLI_asan_poison(ret, iter->pool->esize);
|
||||
}
|
||||
return ret2;
|
||||
}
|
||||
curnode = CHUNK_DATA(iter->curchunk);
|
||||
}
|
||||
@@ -678,6 +971,8 @@ void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
|
||||
do {
|
||||
ret = curnode;
|
||||
|
||||
BLI_asan_unpoison(ret, esize - POISON_REDZONE_SIZE);
|
||||
|
||||
if (++iter->curindex != iter->pool->pchunk) {
|
||||
curnode = POINTER_OFFSET(curnode, esize);
|
||||
}
|
||||
@@ -693,17 +988,37 @@ void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
|
||||
/* pass. */
|
||||
}
|
||||
if (UNLIKELY(iter->curchunk == NULL)) {
|
||||
return (ret->freeword == FREEWORD) ? NULL : ret;
|
||||
if (ret->freeword == FREEWORD) {
|
||||
BLI_asan_poison(ret, esize);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/* End `threadsafe` exception. */
|
||||
|
||||
iter->curchunk = iter->curchunk->next;
|
||||
if (UNLIKELY(iter->curchunk == NULL)) {
|
||||
return (ret->freeword == FREEWORD) ? NULL : ret;
|
||||
if (ret->freeword == FREEWORD) {
|
||||
BLI_asan_poison(ret, iter->pool->esize);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
curnode = CHUNK_DATA(iter->curchunk);
|
||||
}
|
||||
} while (ret->freeword == FREEWORD);
|
||||
|
||||
if (ret->freeword == FREEWORD) {
|
||||
BLI_asan_poison(ret, iter->pool->esize);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -747,7 +1062,7 @@ void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
|
||||
|
||||
do {
|
||||
mpchunk_next = mpchunk->next;
|
||||
mempool_chunk_free(mpchunk);
|
||||
mempool_chunk_free(mpchunk, pool);
|
||||
} while ((mpchunk = mpchunk_next));
|
||||
}
|
||||
|
||||
@@ -781,7 +1096,9 @@ void BLI_mempool_clear(BLI_mempool *pool)
|
||||
*/
|
||||
void BLI_mempool_destroy(BLI_mempool *pool)
|
||||
{
|
||||
mempool_chunk_free_all(pool->chunks);
|
||||
mempool_chunk_free_all(pool->chunks, pool);
|
||||
|
||||
MEM_SAFE_FREE(pool->chunktable);
|
||||
|
||||
#ifdef WITH_MEM_VALGRIND
|
||||
VALGRIND_DESTROY_MEMPOOL(pool);
|
||||
|
153
source/blender/blenlib/intern/BLI_table_gset.c
Normal file
153
source/blender/blenlib/intern/BLI_table_gset.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_compiler_compat.h"
|
||||
#
|
||||
#include "BLI_smallhash.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_ghash.h"
|
||||
|
||||
//#define PTR_TO_IDX(ts) ((GHash *)ts->ptr_to_idx.buckets)
|
||||
#define PTR_TO_IDX(ts) &(ts)->ptr_to_idx
|
||||
|
||||
TableGSet *BLI_table_gset_new(const char *info)
|
||||
{
|
||||
TableGSet *ts = MEM_callocN(sizeof(TableGSet), info);
|
||||
|
||||
// ts->ptr_to_idx.buckets = (void *)BLI_ghash_ptr_new(info);
|
||||
BLI_smallhash_init(&ts->ptr_to_idx);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
TableGSet *BLI_table_gset_new_ex(const char *info, int size)
|
||||
{
|
||||
TableGSet *ts = MEM_callocN(sizeof(TableGSet), info);
|
||||
|
||||
// ts->ptr_to_idx.buckets = (void *)BLI_ghash_ptr_new_ex(info, (uint)size);
|
||||
BLI_smallhash_init(&ts->ptr_to_idx);
|
||||
|
||||
if (size) {
|
||||
ts->elems = MEM_callocN(sizeof(void *) * (uint)size, info);
|
||||
ts->size = size;
|
||||
ts->length = 0;
|
||||
ts->cur = 0;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
void BLI_table_gset_free(TableGSet *ts, GHashKeyFreeFP freefp)
|
||||
{
|
||||
if (!PTR_TO_IDX(ts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ts->elems) {
|
||||
MEM_freeN(ts->elems);
|
||||
}
|
||||
|
||||
// BLI_ghash_free(PTR_TO_IDX(ts), freefp, NULL);
|
||||
BLI_smallhash_release(&ts->ptr_to_idx);
|
||||
|
||||
MEM_freeN(ts);
|
||||
}
|
||||
|
||||
static void table_gset_resize(TableGSet *ts)
|
||||
{
|
||||
if (ts->cur >= ts->size) {
|
||||
uint newsize = (uint)(ts->cur + 1);
|
||||
newsize = (newsize << 1U) - (newsize >> 1U);
|
||||
newsize = MAX2(newsize, 8U);
|
||||
|
||||
if (!ts->elems) {
|
||||
ts->elems = (void *)MEM_mallocN(sizeof(void *) * newsize, "ts->elems");
|
||||
}
|
||||
else {
|
||||
ts->elems = (void *)MEM_reallocN(ts->elems, newsize * sizeof(void *));
|
||||
}
|
||||
|
||||
// BLI_smallhash_clear(PTR_TO_IDX(ts), 0ULL);
|
||||
|
||||
// compact
|
||||
int i = 0, j = 0;
|
||||
for (i = 0; i < ts->cur; i++) {
|
||||
void *elem2 = ts->elems[i];
|
||||
|
||||
if (elem2) {
|
||||
void **val;
|
||||
BLI_smallhash_ensure_p(PTR_TO_IDX(ts), (uintptr_t)elem2, &val);
|
||||
|
||||
// BLI_smallhash_insert(PTR_TO_IDX(ts), elem2, (void *)j);
|
||||
*val = POINTER_FROM_INT(j);
|
||||
|
||||
ts->elems[j++] = elem2;
|
||||
}
|
||||
}
|
||||
|
||||
ts->size = (int)newsize;
|
||||
ts->cur = j;
|
||||
}
|
||||
}
|
||||
|
||||
bool BLI_table_gset_add(TableGSet *ts, void *elem)
|
||||
{
|
||||
void **val;
|
||||
|
||||
table_gset_resize(ts);
|
||||
|
||||
bool ret = BLI_smallhash_ensure_p(PTR_TO_IDX(ts), (uintptr_t)elem, &val);
|
||||
|
||||
if (!ret) {
|
||||
*val = ts->cur;
|
||||
|
||||
ts->elems[ts->cur++] = elem;
|
||||
ts->length++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BLI_table_gset_insert(TableGSet *ts, void *elem)
|
||||
{
|
||||
table_gset_resize(ts);
|
||||
|
||||
BLI_smallhash_insert(PTR_TO_IDX(ts), elem, (void *)ts->cur);
|
||||
|
||||
ts->elems[ts->cur++] = elem;
|
||||
ts->length++;
|
||||
}
|
||||
|
||||
void BLI_table_gset_remove(TableGSet *ts, void *elem, GHashKeyFreeFP freefp)
|
||||
{
|
||||
if (!elem || !ts) {
|
||||
return;
|
||||
}
|
||||
|
||||
int *idx = (int *)BLI_smallhash_lookup_p(PTR_TO_IDX(ts), elem);
|
||||
if (!idx) {
|
||||
return;
|
||||
}
|
||||
|
||||
int idx2 = *idx;
|
||||
|
||||
BLI_smallhash_remove(PTR_TO_IDX(ts), elem);
|
||||
|
||||
if (!ts->elems || ts->elems[idx2] != elem) {
|
||||
return;
|
||||
}
|
||||
|
||||
ts->length--;
|
||||
ts->elems[idx2] = NULL;
|
||||
}
|
||||
|
||||
bool BLI_table_gset_haskey(TableGSet *ts, void *elem)
|
||||
{
|
||||
return BLI_smallhash_haskey(PTR_TO_IDX(ts), elem);
|
||||
}
|
||||
|
||||
int BLI_table_gset_len(TableGSet *ts)
|
||||
{
|
||||
return ts->length;
|
||||
}
|
@@ -55,20 +55,56 @@
|
||||
|
||||
#include "BLI_smallhash.h"
|
||||
|
||||
#include "BLI_asan.h"
|
||||
#include "BLI_strict_flags.h"
|
||||
|
||||
#define SMHASH_KEY_UNUSED ((uintptr_t)(UINTPTR_MAX - 0))
|
||||
#define SMHASH_CELL_FREE ((void *)(UINTPTR_MAX - 1))
|
||||
#define SMHASH_CELL_UNUSED ((void *)(UINTPTR_MAX - 2))
|
||||
#ifdef BLI_asan_poison
|
||||
# undef BLI_asan_poison
|
||||
#endif
|
||||
#ifdef BLI_asan_unpoison
|
||||
# undef BLI_asan_unpoison
|
||||
#endif
|
||||
|
||||
#define BLI_asan_poison(a, b)
|
||||
#define BLI_asan_unpoison(a, b)
|
||||
|
||||
/* NOTE: copied from BLO_blend_defs.h, don't use here because we're in BLI. */
|
||||
#ifdef __BIG_ENDIAN__
|
||||
/* Big Endian */
|
||||
# define MAKE_ID(a, b, c, d) ((int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d))
|
||||
# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
|
||||
((int64_t)(a) << 56 | (int64_t)(b) << 48 | (int64_t)(c) << 40 | (int64_t)(d) << 32 | \
|
||||
(int64_t)(e) << 24 | (int64_t)(f) << 16 | (int64_t)(g) << 8 | (h))
|
||||
#else
|
||||
/* Little Endian */
|
||||
# define MAKE_ID(a, b, c, d) ((int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a))
|
||||
# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
|
||||
((int64_t)(h) << 56 | (int64_t)(g) << 48 | (int64_t)(f) << 40 | (int64_t)(e) << 32 | \
|
||||
(int64_t)(d) << 24 | (int64_t)(c) << 16 | (int64_t)(b) << 8 | (a))
|
||||
#endif
|
||||
|
||||
#define SMHASH_KEY_UNUSED (uintptr_t)(MAKE_ID_8('s', 'm', 'h', 'k', 'u', 'n', 'u', 's'))
|
||||
#define SMHASH_CELL_FREE (uintptr_t)(MAKE_ID_8('s', 'm', 'h', 'c', 'f', 'r', 'e', 'e'))
|
||||
#define SMHASH_CELL_UNUSED (uintptr_t)(MAKE_ID_8('s', 'm', 'h', 'c', 'u', 'n', 'u', 's'))
|
||||
|
||||
#define USE_REMOVE
|
||||
|
||||
/* typically this re-assigns 'h' */
|
||||
#define SMHASH_NEXT(h, hoff) \
|
||||
(CHECK_TYPE_INLINE(&(h), uint *), \
|
||||
CHECK_TYPE_INLINE(&(hoff), uint *), \
|
||||
(CHECK_TYPE_INLINE(&(h), uintptr_t *), \
|
||||
CHECK_TYPE_INLINE(&(hoff), uintptr_t *), \
|
||||
((h) + (((hoff) = ((hoff)*2) + 1), (hoff))))
|
||||
|
||||
/* nothing uses BLI_smallhash_remove yet */
|
||||
// #define USE_REMOVE
|
||||
BLI_INLINE bool check_stack_move(SmallHash *sh)
|
||||
{
|
||||
if (sh->using_stack && sh->buckets != sh->buckets_stack) {
|
||||
sh->buckets = sh->buckets_stack;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_INLINE bool smallhash_val_is_used(const void *val)
|
||||
{
|
||||
@@ -82,28 +118,46 @@ BLI_INLINE bool smallhash_val_is_used(const void *val)
|
||||
extern const uint BLI_ghash_hash_sizes[];
|
||||
#define hashsizes BLI_ghash_hash_sizes
|
||||
|
||||
BLI_INLINE uint smallhash_key(const uintptr_t key)
|
||||
BLI_INLINE uintptr_t smallhash_key(const uintptr_t key)
|
||||
{
|
||||
return (uint)key;
|
||||
#if 1
|
||||
return key;
|
||||
#else
|
||||
uintptr_t y = (size_t)key;
|
||||
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
|
||||
* excessive hash collisions for dicts and sets */
|
||||
|
||||
return (uintptr_t)(y >> 4) | ((uintptr_t)y << (sizeof(uintptr_t[8]) - 4));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the number of items in the smallhash is large enough to require more buckets.
|
||||
*/
|
||||
BLI_INLINE bool smallhash_test_expand_buckets(const uint nentries, const uint nbuckets)
|
||||
BLI_INLINE bool smallhash_test_expand_buckets(const uint nentries,
|
||||
const uint nbuckets,
|
||||
const uint nfreecells)
|
||||
{
|
||||
if (nfreecells < 3) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (approx * 1.5) */
|
||||
return (nentries + (nentries >> 1)) > nbuckets;
|
||||
return (nentries + (nentries >> 1)) > nbuckets || nfreecells < 3;
|
||||
}
|
||||
|
||||
BLI_INLINE void smallhash_init_empty(SmallHash *sh)
|
||||
{
|
||||
uint i;
|
||||
|
||||
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
|
||||
|
||||
for (i = 0; i < sh->nbuckets; i++) {
|
||||
sh->buckets[i].key = SMHASH_KEY_UNUSED;
|
||||
sh->buckets[i].val = SMHASH_CELL_FREE;
|
||||
}
|
||||
|
||||
BLI_asan_poison(&sh->buckets, sizeof(void *));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,19 +165,24 @@ BLI_INLINE void smallhash_init_empty(SmallHash *sh)
|
||||
*/
|
||||
BLI_INLINE void smallhash_buckets_reserve(SmallHash *sh, const uint nentries_reserve)
|
||||
{
|
||||
while (smallhash_test_expand_buckets(nentries_reserve, sh->nbuckets)) {
|
||||
while (smallhash_test_expand_buckets(nentries_reserve, sh->nbuckets, sh->nbuckets + 5)) {
|
||||
sh->nbuckets = hashsizes[++sh->cursize];
|
||||
sh->nfreecells = sh->nbuckets;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE SmallHashEntry *smallhash_lookup(const SmallHash *sh, const uintptr_t key)
|
||||
BLI_INLINE SmallHashEntry *smallhash_lookup(SmallHash *sh, const uintptr_t key)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
SmallHashEntry *e;
|
||||
uint h = smallhash_key(key);
|
||||
uint hoff = 1;
|
||||
uintptr_t h = smallhash_key(key);
|
||||
uintptr_t hoff = 1;
|
||||
|
||||
BLI_assert(key != SMHASH_KEY_UNUSED);
|
||||
|
||||
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
|
||||
|
||||
/* NOTE: there are always more buckets than entries,
|
||||
* so we know there will always be a free bucket if the key isn't found. */
|
||||
for (e = &sh->buckets[h % sh->nbuckets]; e->val != SMHASH_CELL_FREE;
|
||||
@@ -135,25 +194,37 @@ BLI_INLINE SmallHashEntry *smallhash_lookup(const SmallHash *sh, const uintptr_t
|
||||
}
|
||||
}
|
||||
|
||||
BLI_asan_poison(&sh->buckets, sizeof(void *));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BLI_INLINE SmallHashEntry *smallhash_lookup_first_free(SmallHash *sh, const uintptr_t key)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
SmallHashEntry *e;
|
||||
uint h = smallhash_key(key);
|
||||
uint hoff = 1;
|
||||
uintptr_t h = smallhash_key(key);
|
||||
uintptr_t hoff = 1;
|
||||
|
||||
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
|
||||
|
||||
for (e = &sh->buckets[h % sh->nbuckets]; smallhash_val_is_used(e->val);
|
||||
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
|
||||
/* pass */
|
||||
}
|
||||
|
||||
BLI_asan_poison(&sh->buckets, sizeof(void *));
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
BLI_INLINE void smallhash_resize_buckets(SmallHash *sh, const uint nbuckets)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
|
||||
|
||||
SmallHashEntry *buckets_old = sh->buckets;
|
||||
const uint nbuckets_old = sh->nbuckets;
|
||||
const bool was_alloc = (buckets_old != sh->buckets_stack);
|
||||
@@ -169,21 +240,29 @@ BLI_INLINE void smallhash_resize_buckets(SmallHash *sh, const uint nbuckets)
|
||||
}
|
||||
else {
|
||||
sh->buckets = MEM_mallocN(sizeof(*sh->buckets) * nbuckets, __func__);
|
||||
sh->using_stack = false;
|
||||
}
|
||||
|
||||
sh->nbuckets = nbuckets;
|
||||
sh->nfreecells = nbuckets;
|
||||
sh->nentries = 0;
|
||||
|
||||
BLI_asan_poison(&sh->buckets, sizeof(void *));
|
||||
smallhash_init_empty(sh);
|
||||
|
||||
for (i = 0; i < nbuckets_old; i++) {
|
||||
if (smallhash_val_is_used(buckets_old[i].val)) {
|
||||
SmallHashEntry *e = smallhash_lookup_first_free(sh, buckets_old[i].key);
|
||||
|
||||
e->key = buckets_old[i].key;
|
||||
e->val = buckets_old[i].val;
|
||||
|
||||
sh->nfreecells--;
|
||||
sh->nentries++;
|
||||
}
|
||||
}
|
||||
|
||||
if (was_alloc) {
|
||||
if (was_alloc && buckets_old) {
|
||||
MEM_freeN(buckets_old);
|
||||
}
|
||||
}
|
||||
@@ -194,15 +273,23 @@ void BLI_smallhash_init_ex(SmallHash *sh, const uint nentries_reserve)
|
||||
|
||||
sh->nentries = 0;
|
||||
sh->cursize = 2;
|
||||
sh->using_stack = true;
|
||||
sh->nbuckets = hashsizes[sh->cursize];
|
||||
sh->nfreecells = sh->nbuckets;
|
||||
|
||||
sh->buckets = sh->buckets_stack;
|
||||
|
||||
BLI_asan_poison(&sh->buckets, sizeof(void *));
|
||||
|
||||
if (nentries_reserve) {
|
||||
smallhash_buckets_reserve(sh, nentries_reserve);
|
||||
|
||||
if (sh->nbuckets > SMSTACKSIZE) {
|
||||
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
|
||||
sh->buckets = MEM_mallocN(sizeof(*sh->buckets) * sh->nbuckets, __func__);
|
||||
BLI_asan_poison(&sh->buckets, sizeof(void *));
|
||||
|
||||
sh->using_stack = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,24 +304,85 @@ void BLI_smallhash_init(SmallHash *sh)
|
||||
/* NOTE: does *not* free *sh itself! only the direct data! */
|
||||
void BLI_smallhash_release(SmallHash *sh)
|
||||
{
|
||||
if (sh->buckets != sh->buckets_stack) {
|
||||
check_stack_move(sh);
|
||||
|
||||
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
|
||||
|
||||
if (sh->buckets && sh->buckets != sh->buckets_stack) {
|
||||
MEM_freeN(sh->buckets);
|
||||
}
|
||||
}
|
||||
|
||||
bool BLI_smallhash_ensure_p(SmallHash *sh, uintptr_t key, void ***item)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
SmallHashEntry *e = NULL;
|
||||
uintptr_t h = smallhash_key(key);
|
||||
uintptr_t hoff = 1;
|
||||
|
||||
if (UNLIKELY(smallhash_test_expand_buckets(sh->nentries, sh->nbuckets, sh->nfreecells))) {
|
||||
smallhash_resize_buckets(sh, hashsizes[++sh->cursize]);
|
||||
}
|
||||
|
||||
BLI_assert(key != SMHASH_KEY_UNUSED);
|
||||
|
||||
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
|
||||
|
||||
/* NOTE: there are always more buckets than entries,
|
||||
* so we know there will always be a free bucket if the key isn't found. */
|
||||
for (e = &sh->buckets[h % sh->nbuckets]; e->val != SMHASH_CELL_FREE;
|
||||
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
|
||||
if (e->key == key) {
|
||||
/* should never happen because unused keys are zero'd */
|
||||
BLI_assert(e->val != SMHASH_CELL_UNUSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_asan_poison(&sh->buckets, sizeof(void *));
|
||||
|
||||
bool ret;
|
||||
|
||||
if (e->val == SMHASH_CELL_FREE || e->val == SMHASH_CELL_UNUSED) {
|
||||
sh->nentries++;
|
||||
sh->nfreecells--;
|
||||
ret = false;
|
||||
}
|
||||
else {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
e->key = key;
|
||||
*item = &e->val;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
SmallHashEntry *e;
|
||||
|
||||
BLI_assert(key != SMHASH_KEY_UNUSED);
|
||||
BLI_assert(smallhash_val_is_used(item));
|
||||
BLI_assert(BLI_smallhash_haskey(sh, key) == false);
|
||||
|
||||
if (UNLIKELY(smallhash_test_expand_buckets(++sh->nentries, sh->nbuckets))) {
|
||||
if (UNLIKELY(smallhash_test_expand_buckets(sh->nentries, sh->nbuckets, sh->nfreecells))) {
|
||||
smallhash_resize_buckets(sh, hashsizes[++sh->cursize]);
|
||||
}
|
||||
|
||||
e = smallhash_lookup_first_free(sh, key);
|
||||
|
||||
if (e->val == SMHASH_CELL_FREE) {
|
||||
sh->nentries++;
|
||||
sh->nfreecells--;
|
||||
}
|
||||
else if (e->val == SMHASH_CELL_UNUSED) {
|
||||
sh->nentries++;
|
||||
}
|
||||
|
||||
e->key = key;
|
||||
e->val = item;
|
||||
}
|
||||
@@ -260,10 +408,47 @@ bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item)
|
||||
|
||||
#ifdef USE_REMOVE
|
||||
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
// SmallHashEntry *e = smallhash_lookup(sh, key);
|
||||
|
||||
SmallHashEntry *e;
|
||||
uintptr_t h = smallhash_key(key);
|
||||
uintptr_t hoff = 1;
|
||||
|
||||
for (e = &sh->buckets[h % sh->nbuckets]; e->val != SMHASH_CELL_FREE;
|
||||
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
|
||||
if (e->key == key) {
|
||||
/* should never happen because unused keys are zero'd */
|
||||
BLI_assert(e->val != SMHASH_CELL_UNUSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (e && e->key == key) {
|
||||
h = SMHASH_NEXT(h, hoff);
|
||||
SmallHashEntry *e2 = &sh->buckets[h & sh->nbuckets];
|
||||
|
||||
e->key = SMHASH_KEY_UNUSED;
|
||||
e->val = SMHASH_CELL_UNUSED;
|
||||
|
||||
sh->nentries--;
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BLI_smallhash_remove_p(SmallHash *sh, uintptr_t key, void **val)
|
||||
{
|
||||
SmallHashEntry *e = smallhash_lookup(sh, key);
|
||||
|
||||
if (e) {
|
||||
*val = e->val;
|
||||
|
||||
e->key = SMHASH_KEY_UNUSED;
|
||||
e->val = SMHASH_CELL_UNUSED;
|
||||
sh->nentries--;
|
||||
@@ -276,34 +461,54 @@ bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key)
|
||||
}
|
||||
#endif
|
||||
|
||||
void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
|
||||
void *BLI_smallhash_lookup(SmallHash *sh, uintptr_t key)
|
||||
{
|
||||
SmallHashEntry *e = smallhash_lookup(sh, key);
|
||||
|
||||
return e ? e->val : NULL;
|
||||
}
|
||||
|
||||
void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key)
|
||||
void **BLI_smallhash_lookup_p(SmallHash *sh, uintptr_t key)
|
||||
{
|
||||
SmallHashEntry *e = smallhash_lookup(sh, key);
|
||||
|
||||
return e ? &e->val : NULL;
|
||||
}
|
||||
|
||||
bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key)
|
||||
void BLI_smallhash_clear(SmallHash *sh, uintptr_t key)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
|
||||
|
||||
SmallHashEntry *e = sh->buckets;
|
||||
|
||||
for (uint i = 0; i < sh->nbuckets; i++, e++) {
|
||||
e->key = SMHASH_KEY_UNUSED;
|
||||
e->val = SMHASH_CELL_FREE;
|
||||
}
|
||||
|
||||
sh->nentries = 0;
|
||||
|
||||
BLI_asan_poison(&sh->buckets, sizeof(void *));
|
||||
}
|
||||
|
||||
bool BLI_smallhash_haskey(SmallHash *sh, uintptr_t key)
|
||||
{
|
||||
SmallHashEntry *e = smallhash_lookup(sh, key);
|
||||
|
||||
return (e != NULL);
|
||||
}
|
||||
|
||||
int BLI_smallhash_len(const SmallHash *sh)
|
||||
int BLI_smallhash_len(SmallHash *sh)
|
||||
{
|
||||
return (int)sh->nentries;
|
||||
}
|
||||
|
||||
BLI_INLINE SmallHashEntry *smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
|
||||
{
|
||||
BLI_asan_unpoison(&iter->sh->buckets, sizeof(void *));
|
||||
|
||||
while (iter->i < iter->sh->nbuckets) {
|
||||
if (smallhash_val_is_used(iter->sh->buckets[iter->i].val)) {
|
||||
if (key) {
|
||||
@@ -316,6 +521,7 @@ BLI_INLINE SmallHashEntry *smallhash_iternext(SmallHashIter *iter, uintptr_t *ke
|
||||
iter->i++;
|
||||
}
|
||||
|
||||
BLI_asan_poison(&iter->sh->buckets, sizeof(void *));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -333,16 +539,20 @@ void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key)
|
||||
return e ? &e->val : NULL;
|
||||
}
|
||||
|
||||
void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
|
||||
void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
iter->sh = sh;
|
||||
iter->i = 0;
|
||||
|
||||
return BLI_smallhash_iternext(iter, key);
|
||||
}
|
||||
|
||||
void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
|
||||
void **BLI_smallhash_iternew_p(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
|
||||
{
|
||||
check_stack_move(sh);
|
||||
|
||||
iter->sh = sh;
|
||||
iter->i = 0;
|
||||
|
||||
@@ -408,8 +618,8 @@ double BLI_smallhash_calc_quality(SmallHash *sh)
|
||||
if (sh->buckets[i].key != SMHASH_KEY_UNUSED) {
|
||||
uint64_t count = 0;
|
||||
SmallHashEntry *e, *e_final = &sh->buckets[i];
|
||||
uint h = smallhash_key(e_final->key);
|
||||
uint hoff = 1;
|
||||
uintptr_t h = smallhash_key(e_final->key);
|
||||
uintptr_t hoff = 1;
|
||||
|
||||
for (e = &sh->buckets[h % sh->nbuckets]; e != e_final;
|
||||
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
|
||||
|
@@ -90,7 +90,8 @@ class Task {
|
||||
other.freedata = nullptr;
|
||||
}
|
||||
|
||||
#if defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10
|
||||
#if (defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10) || \
|
||||
(defined(__clang__) && defined(WIN32))
|
||||
Task(const Task &other)
|
||||
: pool(other.pool),
|
||||
run(other.run),
|
||||
|
@@ -2420,7 +2420,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
/* this can now be turned off */
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
if (ts->sculpt) {
|
||||
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE;
|
||||
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_CLEANUP;
|
||||
}
|
||||
|
||||
/* 'Increment' mode disabled for nodes, use true grid snapping instead */
|
||||
|
@@ -4424,7 +4424,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
|
||||
ups->flag &= ~(UNIFIED_PAINT_FLAG_UNUSED_0 | UNIFIED_PAINT_FLAG_UNUSED_1);
|
||||
ups->flag &= ~(UNIFIED_PAINT_FLAG_UNUSED_1);
|
||||
}
|
||||
|
||||
/* Set the default render pass in the viewport to Combined. */
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_fluid_types.h"
|
||||
#include "DNA_genfile.h"
|
||||
#include "DNA_gpencil_modifier_types.h"
|
||||
@@ -55,6 +56,7 @@
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_brush.h"
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_colortools.h"
|
||||
#include "BKE_cryptomatte.h"
|
||||
@@ -1940,6 +1942,13 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "diff_fac")) {
|
||||
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
|
||||
light->diff_fac = 1.0f;
|
||||
light->volume_fac = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 293, 15)) {
|
||||
|
@@ -48,6 +48,7 @@
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_asset.h"
|
||||
#include "BKE_brush.h"
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_fcurve.h"
|
||||
@@ -1229,6 +1230,93 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 21)) {
|
||||
LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
|
||||
/* try to detect beta testers' files by seeing
|
||||
if autosmooth_fset_slide is 0; this will
|
||||
not work once it is added to DNA defaults
|
||||
(right now it's being set in BKE_brush_sculpt_reset).*/
|
||||
if (br->autosmooth_fset_slide == 0.0f) {
|
||||
Brush defbrush = *br;
|
||||
|
||||
BKE_brush_sculpt_reset(&defbrush);
|
||||
br->dyntopo = defbrush.dyntopo;
|
||||
|
||||
br->flag2 |= defbrush.flag2 & (BRUSH_SMOOTH_PRESERVE_FACE_SETS |
|
||||
BRUSH_SMOOTH_USE_AREA_WEIGHT | BRUSH_CURVATURE_RAKE);
|
||||
|
||||
br->autosmooth_fset_slide = defbrush.autosmooth_fset_slide;
|
||||
br->boundary_smooth_factor = defbrush.boundary_smooth_factor;
|
||||
br->autosmooth_spacing = defbrush.autosmooth_spacing;
|
||||
br->autosmooth_radius_factor = defbrush.autosmooth_radius_factor;
|
||||
br->topology_rake_radius_factor = defbrush.topology_rake_radius_factor;
|
||||
br->topology_rake_projection = defbrush.topology_rake_projection;
|
||||
br->topology_rake_spacing = defbrush.topology_rake_spacing;
|
||||
|
||||
if (br->autosmooth_projection == 0.0f) {
|
||||
br->autosmooth_projection = defbrush.autosmooth_projection;
|
||||
}
|
||||
}
|
||||
|
||||
if (br->sculpt_tool == SCULPT_TOOL_VCOL_BOUNDARY) {
|
||||
if (br->vcol_boundary_exponent == 0.0f) {
|
||||
br->vcol_boundary_exponent = 1.0f;
|
||||
}
|
||||
}
|
||||
else if (br->sculpt_tool == SCULPT_TOOL_SIMPLIFY) {
|
||||
br->dyntopo.inherit = DYNTOPO_INHERIT_BITMASK &
|
||||
~(DYNTOPO_INHERIT_ALL | DYNTOPO_SUBDIVIDE | DYNTOPO_COLLAPSE);
|
||||
br->dyntopo.flag |= DYNTOPO_COLLAPSE | DYNTOPO_SUBDIVIDE | DYNTOPO_CLEANUP;
|
||||
}
|
||||
}
|
||||
|
||||
Scene *scene;
|
||||
for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
if (ts->sculpt) {
|
||||
ts->sculpt->flags |= SCULPT_DYNTOPO_CLEANUP;
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
if (ts && ts->sculpt) {
|
||||
ts->sculpt->detail_range = 0.4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 22)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
if (ts) {
|
||||
ts->unified_paint_settings.flag |= UNIFIED_PAINT_FLAG_HARD_EDGE_MODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 22)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
if (ts) {
|
||||
ts->unified_paint_settings.flag |= UNIFIED_PAINT_FLAG_HARD_EDGE_MODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 23)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
if (ts && ts->sculpt) {
|
||||
ts->sculpt->flags |= SCULPT_DYNTOPO_ENABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 22)) {
|
||||
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
||||
if (ntree->type == NTREE_GEOMETRY) {
|
||||
@@ -1248,19 +1336,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
* \note Be sure to check when bumping the version:
|
||||
* - "versioning_userdef.c", #blo_do_versions_userdef
|
||||
* - "versioning_userdef.c", #do_versions_theme
|
||||
*
|
||||
* \note Keep this message at the bottom of the function.
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
|
||||
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
@@ -1275,4 +1350,17 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
* \note Be sure to check when bumping the version:
|
||||
* - "versioning_userdef.c", #blo_do_versions_userdef
|
||||
* - "versioning_userdef.c", #do_versions_theme
|
||||
*
|
||||
* \note Keep this message at the bottom of the function.
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
}
|
||||
}
|
||||
|
@@ -688,6 +688,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
|
||||
brush->sculpt_tool = SCULPT_TOOL_PAINT;
|
||||
}
|
||||
|
||||
brush_name = "Color Boundary";
|
||||
brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
|
||||
if (!brush) {
|
||||
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
|
||||
id_us_min(&brush->id);
|
||||
brush->sculpt_tool = SCULPT_TOOL_VCOL_BOUNDARY;
|
||||
}
|
||||
|
||||
brush_name = "Smear";
|
||||
brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
|
||||
if (!brush) {
|
||||
|
@@ -99,6 +99,7 @@ set(SRC
|
||||
intern/bmesh_mesh.c
|
||||
intern/bmesh_mesh.h
|
||||
intern/bmesh_mesh_convert.c
|
||||
intern/bmesh_mesh_convert_threaded.c
|
||||
intern/bmesh_mesh_convert.h
|
||||
intern/bmesh_mesh_duplicate.c
|
||||
intern/bmesh_mesh_duplicate.h
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
/** \file
|
||||
* \ingroup bmesh
|
||||
*
|
||||
@@ -34,6 +36,7 @@ struct BMFace;
|
||||
struct BMLoop;
|
||||
struct BMVert;
|
||||
struct BMesh;
|
||||
struct GSet;
|
||||
|
||||
struct MLoopNorSpaceArray;
|
||||
|
||||
@@ -295,6 +298,10 @@ typedef struct BMFlagLayer {
|
||||
|
||||
// #pragma GCC diagnostic ignored "-Wpadded"
|
||||
|
||||
struct RangeTreeUInt;
|
||||
|
||||
//#define WITH_BM_ID_FREELIST
|
||||
|
||||
typedef struct BMesh {
|
||||
int totvert, totedge, totloop, totface;
|
||||
int totvertsel, totedgesel, totfacesel;
|
||||
@@ -378,8 +385,35 @@ typedef struct BMesh {
|
||||
* instead of crashing on invalid memory access.
|
||||
*/
|
||||
void *py_handle;
|
||||
MultiresModifierData multires; // copy of multires settings
|
||||
bool haveMultiResSettings;
|
||||
int multiresSpace;
|
||||
|
||||
struct {
|
||||
int flag;
|
||||
#ifdef WITH_BM_ID_FREELIST
|
||||
uint *freelist;
|
||||
int freelist_len, freelist_size;
|
||||
struct GSet *free_ids;
|
||||
#else
|
||||
struct RangeTreeUInt *idtree;
|
||||
#endif
|
||||
uint maxid;
|
||||
struct BMElem **map; // used if BM_NO_REUSE_IDS is false
|
||||
struct GHash *ghash; // used if BM_NO_REUSE_IDS is true
|
||||
int map_size;
|
||||
int cd_id_off[15];
|
||||
} idmap;
|
||||
} BMesh;
|
||||
|
||||
enum {
|
||||
// firsst four bits are reserved for BM_VERT/EDGE/LOOP/FACE
|
||||
BM_HAS_IDS = 1 << 4,
|
||||
BM_HAS_ID_MAP = 1 << 5,
|
||||
BM_NO_REUSE_IDS = 1 << 6,
|
||||
BM_PERMANENT_IDS = 1 << 7
|
||||
};
|
||||
|
||||
/** #BMHeader.htype (char) */
|
||||
enum {
|
||||
BM_VERT = 1,
|
||||
@@ -588,3 +622,7 @@ typedef bool (*BMLoopPairFilterFunc)(const BMLoop *, const BMLoop *, void *user_
|
||||
#else
|
||||
# define BM_OMP_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* note does not check if ids are enabled for a given element type */
|
||||
#define BM_ELEM_GET_ID(bm, elem) \
|
||||
BM_ELEM_CD_GET_INT(elem, bm->idmap.cd_id_off[(int)(elem)->head.htype])
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user