UI: Region polling support #105088
|
@ -53,7 +53,18 @@ This package provides Blender as a Python module for use in studio pipelines, we
|
|||
|
||||
[System requirements](https://www.blender.org/download/requirements/) are the same as Blender.
|
||||
|
||||
Each Blender release supports one Python version, and the package is only compatible with that version."""
|
||||
Each Blender release supports one Python version, and the package is only compatible with that version.
|
||||
|
||||
## Source Code
|
||||
|
||||
* [Releases](https://download.blender.org/source/)
|
||||
* Repository: [git.blender.org/blender.git](https://git.blender.org/gitweb/gitweb.cgi/blender.git)
|
||||
|
||||
## Credits
|
||||
|
||||
Created by the [Blender developer community](https://www.blender.org/about/credits/).
|
||||
|
||||
Thanks to Tyler Alden Gubala for maintaining the original version of this package."""
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Generic Functions
|
||||
|
|
|
@ -1085,11 +1085,11 @@ static void create_subd_mesh(Scene *scene,
|
|||
const int edges_num = b_mesh.edges.length();
|
||||
|
||||
if (edges_num != 0 && b_mesh.edge_creases.length() > 0) {
|
||||
size_t num_creases = 0;
|
||||
const float *creases = static_cast<float *>(b_mesh.edge_creases[0].ptr.data);
|
||||
BL::MeshEdgeCreaseLayer creases = b_mesh.edge_creases[0];
|
||||
|
||||
size_t num_creases = 0;
|
||||
for (int i = 0; i < edges_num; i++) {
|
||||
if (creases[i] != 0.0f) {
|
||||
if (creases.data[i].value() != 0.0f) {
|
||||
num_creases++;
|
||||
}
|
||||
}
|
||||
|
@ -1098,17 +1098,18 @@ static void create_subd_mesh(Scene *scene,
|
|||
|
||||
const MEdge *edges = static_cast<MEdge *>(b_mesh.edges[0].ptr.data);
|
||||
for (int i = 0; i < edges_num; i++) {
|
||||
if (creases[i] != 0.0f) {
|
||||
const float crease = creases.data[i].value();
|
||||
if (crease != 0.0f) {
|
||||
const MEdge &b_edge = edges[i];
|
||||
mesh->add_edge_crease(b_edge.v1, b_edge.v2, creases[i]);
|
||||
mesh->add_edge_crease(b_edge.v1, b_edge.v2, crease);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (BL::MeshVertexCreaseLayer &c : b_mesh.vertex_creases) {
|
||||
for (int i = 0; i < c.data.length(); ++i) {
|
||||
if (c.data[i].value() != 0.0f) {
|
||||
mesh->add_vertex_crease(i, c.data[i].value());
|
||||
}
|
||||
for (BL::MeshVertexCreaseLayer &c : b_mesh.vertex_creases) {
|
||||
for (int i = 0; i < c.data.length(); ++i) {
|
||||
if (c.data[i].value() != 0.0f) {
|
||||
mesh->add_vertex_crease(i, c.data[i].value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,584 +1,6 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright 2011-2022 Blender Foundation
|
||||
|
||||
###########################################################################
|
||||
# Helper macros
|
||||
###########################################################################
|
||||
|
||||
macro(_set_default variable value)
|
||||
if(NOT ${variable})
|
||||
set(${variable} ${value})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
###########################################################################
|
||||
# Precompiled libraries detection
|
||||
#
|
||||
# Use precompiled libraries from Blender repository
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if(APPLE)
|
||||
if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64")
|
||||
set(_cycles_lib_dir "${CMAKE_SOURCE_DIR}/../lib/darwin")
|
||||
else()
|
||||
set(_cycles_lib_dir "${CMAKE_SOURCE_DIR}/../lib/darwin_arm64")
|
||||
endif()
|
||||
|
||||
# Always use system zlib
|
||||
find_package(ZLIB REQUIRED)
|
||||
elseif(WIN32)
|
||||
if(CMAKE_CL_64)
|
||||
set(_cycles_lib_dir "${CMAKE_SOURCE_DIR}/../lib/win64_vc15")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported Visual Studio Version")
|
||||
endif()
|
||||
else()
|
||||
# Path to a locally compiled libraries.
|
||||
set(LIBDIR_NAME ${CMAKE_SYSTEM_NAME}_${CMAKE_SYSTEM_PROCESSOR})
|
||||
string(TOLOWER ${LIBDIR_NAME} LIBDIR_NAME)
|
||||
set(LIBDIR_NATIVE_ABI ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_NAME})
|
||||
|
||||
# Path to precompiled libraries with known CentOS 7 ABI.
|
||||
set(LIBDIR_CENTOS7_ABI ${CMAKE_SOURCE_DIR}/../lib/linux_centos7_x86_64)
|
||||
|
||||
# Choose the best suitable libraries.
|
||||
if(EXISTS ${LIBDIR_NATIVE_ABI})
|
||||
set(_cycles_lib_dir ${LIBDIR_NATIVE_ABI})
|
||||
elseif(EXISTS ${LIBDIR_CENTOS7_ABI})
|
||||
set(_cycles_lib_dir ${LIBDIR_CENTOS7_ABI})
|
||||
set(WITH_CXX11_ABI OFF)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC AND
|
||||
CMAKE_C_COMPILER_VERSION VERSION_LESS 9.3)
|
||||
message(FATAL_ERROR "GCC version must be at least 9.3 for precompiled libraries, found ${CMAKE_C_COMPILER_VERSION}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DEFINED _cycles_lib_dir)
|
||||
message(STATUS "Using precompiled libraries at ${_cycles_lib_dir}")
|
||||
endif()
|
||||
|
||||
# Avoid namespace pollustion.
|
||||
unset(LIBDIR_NATIVE_ABI)
|
||||
unset(LIBDIR_CENTOS7_ABI)
|
||||
endif()
|
||||
|
||||
if(EXISTS ${_cycles_lib_dir})
|
||||
_set_default(ALEMBIC_ROOT_DIR "${_cycles_lib_dir}/alembic")
|
||||
_set_default(BOOST_ROOT "${_cycles_lib_dir}/boost")
|
||||
_set_default(BLOSC_ROOT_DIR "${_cycles_lib_dir}/blosc")
|
||||
_set_default(EMBREE_ROOT_DIR "${_cycles_lib_dir}/embree")
|
||||
_set_default(EPOXY_ROOT_DIR "${_cycles_lib_dir}/epoxy")
|
||||
_set_default(IMATH_ROOT_DIR "${_cycles_lib_dir}/imath")
|
||||
_set_default(GLEW_ROOT_DIR "${_cycles_lib_dir}/glew")
|
||||
_set_default(JPEG_ROOT "${_cycles_lib_dir}/jpeg")
|
||||
_set_default(LLVM_ROOT_DIR "${_cycles_lib_dir}/llvm")
|
||||
_set_default(CLANG_ROOT_DIR "${_cycles_lib_dir}/llvm")
|
||||
_set_default(NANOVDB_ROOT_DIR "${_cycles_lib_dir}/openvdb")
|
||||
_set_default(OPENCOLORIO_ROOT_DIR "${_cycles_lib_dir}/opencolorio")
|
||||
_set_default(OPENEXR_ROOT_DIR "${_cycles_lib_dir}/openexr")
|
||||
_set_default(OPENIMAGEDENOISE_ROOT_DIR "${_cycles_lib_dir}/openimagedenoise")
|
||||
_set_default(OPENIMAGEIO_ROOT_DIR "${_cycles_lib_dir}/openimageio")
|
||||
_set_default(OPENJPEG_ROOT_DIR "${_cycles_lib_dir}/openjpeg")
|
||||
_set_default(OPENSUBDIV_ROOT_DIR "${_cycles_lib_dir}/opensubdiv")
|
||||
_set_default(OPENVDB_ROOT_DIR "${_cycles_lib_dir}/openvdb")
|
||||
_set_default(OSL_ROOT_DIR "${_cycles_lib_dir}/osl")
|
||||
_set_default(PNG_ROOT "${_cycles_lib_dir}/png")
|
||||
_set_default(PUGIXML_ROOT_DIR "${_cycles_lib_dir}/pugixml")
|
||||
_set_default(SDL2_ROOT_DIR "${_cycles_lib_dir}/sdl")
|
||||
_set_default(TBB_ROOT_DIR "${_cycles_lib_dir}/tbb")
|
||||
_set_default(TIFF_ROOT "${_cycles_lib_dir}/tiff")
|
||||
_set_default(USD_ROOT_DIR "${_cycles_lib_dir}/usd")
|
||||
_set_default(WEBP_ROOT_DIR "${_cycles_lib_dir}/webp")
|
||||
_set_default(ZLIB_ROOT "${_cycles_lib_dir}/zlib")
|
||||
if(WIN32)
|
||||
set(LEVEL_ZERO_ROOT_DIR ${_cycles_lib_dir}/level_zero)
|
||||
else()
|
||||
set(LEVEL_ZERO_ROOT_DIR ${_cycles_lib_dir}/level-zero)
|
||||
endif()
|
||||
_set_default(SYCL_ROOT_DIR "${_cycles_lib_dir}/dpcpp")
|
||||
|
||||
# Ignore system libraries
|
||||
set(CMAKE_IGNORE_PATH "${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES};${CMAKE_SYSTEM_INCLUDE_PATH};${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES};${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}")
|
||||
else()
|
||||
unset(_cycles_lib_dir)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# Zlib
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(ZLIB_INCLUDE_DIRS ${_cycles_lib_dir}/zlib/include)
|
||||
set(ZLIB_LIBRARIES ${_cycles_lib_dir}/zlib/lib/libz_st.lib)
|
||||
set(ZLIB_INCLUDE_DIR ${_cycles_lib_dir}/zlib/include)
|
||||
set(ZLIB_LIBRARY ${_cycles_lib_dir}/zlib/lib/libz_st.lib)
|
||||
set(ZLIB_DIR ${_cycles_lib_dir}/zlib)
|
||||
set(ZLIB_FOUND ON)
|
||||
elseif(NOT APPLE)
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# PThreads
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(PTHREADS_LIBRARIES "${_cycles_lib_dir}/pthreads/lib/pthreadVC3.lib")
|
||||
include_directories("${_cycles_lib_dir}/pthreads/include")
|
||||
else()
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
set(PTHREADS_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# OpenImageIO and image libraries
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
add_definitions(
|
||||
# OIIO changed the name of this define in newer versions
|
||||
# we define both, so it would work with both old and new
|
||||
# versions.
|
||||
-DOIIO_STATIC_BUILD
|
||||
-DOIIO_STATIC_DEFINE
|
||||
)
|
||||
|
||||
set(OPENIMAGEIO_INCLUDE_DIR ${OPENIMAGEIO_ROOT_DIR}/include)
|
||||
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO_INCLUDE_DIR} ${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO)
|
||||
# Special exceptions for libraries which needs explicit debug version
|
||||
set(OPENIMAGEIO_LIBRARIES
|
||||
optimized ${OPENIMAGEIO_ROOT_DIR}/lib/OpenImageIO.lib
|
||||
optimized ${OPENIMAGEIO_ROOT_DIR}/lib/OpenImageIO_Util.lib
|
||||
debug ${OPENIMAGEIO_ROOT_DIR}/lib/OpenImageIO_d.lib
|
||||
debug ${OPENIMAGEIO_ROOT_DIR}/lib/OpenImageIO_Util_d.lib
|
||||
)
|
||||
|
||||
set(PUGIXML_INCLUDE_DIR ${PUGIXML_ROOT_DIR}/include)
|
||||
set(PUGIXML_LIBRARIES
|
||||
optimized ${PUGIXML_ROOT_DIR}/lib/pugixml.lib
|
||||
debug ${PUGIXML_ROOT_DIR}/lib/pugixml_d.lib
|
||||
)
|
||||
else()
|
||||
find_package(OpenImageIO REQUIRED)
|
||||
if(OPENIMAGEIO_PUGIXML_FOUND)
|
||||
set(PUGIXML_INCLUDE_DIR "${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO")
|
||||
set(PUGIXML_LIBRARIES "")
|
||||
else()
|
||||
find_package(PugiXML REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Dependencies
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(OPENJPEG_INCLUDE_DIR ${OPENJPEG}/include/openjpeg-2.3)
|
||||
set(OPENJPEG_LIBRARIES ${_cycles_lib_dir}/openjpeg/lib/openjp2${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
else()
|
||||
find_package(OpenJPEG REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(JPEG REQUIRED)
|
||||
find_package(TIFF REQUIRED)
|
||||
find_package(WebP)
|
||||
|
||||
if(EXISTS ${_cycles_lib_dir})
|
||||
set(PNG_NAMES png16 libpng16 png libpng)
|
||||
endif()
|
||||
find_package(PNG REQUIRED)
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# OpenEXR
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(OPENEXR_INCLUDE_DIR ${OPENEXR_ROOT_DIR}/include)
|
||||
set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR_ROOT_DIR}/include/OpenEXR ${IMATH_ROOT_DIR}/include ${IMATH_ROOT_DIR}/include/Imath)
|
||||
set(OPENEXR_LIBRARIES
|
||||
optimized ${OPENEXR_ROOT_DIR}/lib/OpenEXR_s.lib
|
||||
optimized ${OPENEXR_ROOT_DIR}/lib/OpenEXRCore_s.lib
|
||||
optimized ${OPENEXR_ROOT_DIR}/lib/Iex_s.lib
|
||||
optimized ${IMATH_ROOT_DIR}/lib/Imath_s.lib
|
||||
optimized ${OPENEXR_ROOT_DIR}/lib/IlmThread_s.lib
|
||||
debug ${OPENEXR_ROOT_DIR}/lib/OpenEXR_s_d.lib
|
||||
debug ${OPENEXR_ROOT_DIR}/lib/OpenEXRCore_s_d.lib
|
||||
debug ${OPENEXR_ROOT_DIR}/lib/Iex_s_d.lib
|
||||
debug ${IMATH_ROOT_DIR}/lib/Imath_s_d.lib
|
||||
debug ${OPENEXR_ROOT_DIR}/lib/IlmThread_s_d.lib
|
||||
)
|
||||
else()
|
||||
find_package(OpenEXR REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# OpenShadingLanguage & LLVM
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_OSL)
|
||||
if(EXISTS ${_cycles_lib_dir})
|
||||
set(LLVM_STATIC ON)
|
||||
endif()
|
||||
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
# TODO(sergey): On Windows llvm-config doesn't give proper results for the
|
||||
# library names, use hardcoded libraries for now.
|
||||
file(GLOB _llvm_libs_release ${LLVM_ROOT_DIR}/lib/*.lib)
|
||||
file(GLOB _llvm_libs_debug ${LLVM_ROOT_DIR}/debug/lib/*.lib)
|
||||
set(_llvm_libs)
|
||||
foreach(_llvm_lib_path ${_llvm_libs_release})
|
||||
get_filename_component(_llvm_lib_name ${_llvm_lib_path} ABSOLUTE)
|
||||
list(APPEND _llvm_libs optimized ${_llvm_lib_name})
|
||||
endforeach()
|
||||
foreach(_llvm_lib_path ${_llvm_libs_debug})
|
||||
get_filename_component(_llvm_lib_name ${_llvm_lib_path} ABSOLUTE)
|
||||
list(APPEND _llvm_libs debug ${_llvm_lib_name})
|
||||
endforeach()
|
||||
set(LLVM_LIBRARY ${_llvm_libs})
|
||||
unset(_llvm_lib_name)
|
||||
unset(_llvm_lib_path)
|
||||
unset(_llvm_libs)
|
||||
unset(_llvm_libs_debug)
|
||||
unset(_llvm_libs_release)
|
||||
|
||||
set(OSL_INCLUDE_DIR ${OSL_ROOT_DIR}/include)
|
||||
set(OSL_LIBRARIES
|
||||
optimized ${OSL_ROOT_DIR}/lib/oslcomp.lib
|
||||
optimized ${OSL_ROOT_DIR}/lib/oslexec.lib
|
||||
optimized ${OSL_ROOT_DIR}/lib/oslquery.lib
|
||||
debug ${OSL_ROOT_DIR}/lib/oslcomp_d.lib
|
||||
debug ${OSL_ROOT_DIR}/lib/oslexec_d.lib
|
||||
debug ${OSL_ROOT_DIR}/lib/oslquery_d.lib
|
||||
${PUGIXML_LIBRARIES}
|
||||
)
|
||||
|
||||
find_program(OSL_COMPILER NAMES oslc PATHS ${OSL_ROOT_DIR}/bin)
|
||||
else()
|
||||
find_package(OSL REQUIRED)
|
||||
find_package(LLVM REQUIRED)
|
||||
find_package(Clang REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# OpenPGL
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_PATH_GUIDING)
|
||||
if(NOT openpgl_DIR AND EXISTS ${_cycles_lib_dir})
|
||||
set(openpgl_DIR ${_cycles_lib_dir}/openpgl/lib/cmake/openpgl)
|
||||
endif()
|
||||
|
||||
find_package(openpgl QUIET)
|
||||
if(openpgl_FOUND)
|
||||
if(WIN32)
|
||||
get_target_property(OPENPGL_LIBRARIES_RELEASE openpgl::openpgl LOCATION_RELEASE)
|
||||
get_target_property(OPENPGL_LIBRARIES_DEBUG openpgl::openpgl LOCATION_DEBUG)
|
||||
set(OPENPGL_LIBRARIES optimized ${OPENPGL_LIBRARIES_RELEASE} debug ${OPENPGL_LIBRARIES_DEBUG})
|
||||
else()
|
||||
get_target_property(OPENPGL_LIBRARIES openpgl::openpgl LOCATION)
|
||||
endif()
|
||||
get_target_property(OPENPGL_INCLUDE_DIR openpgl::openpgl INTERFACE_INCLUDE_DIRECTORIES)
|
||||
else()
|
||||
set_and_warn_library_found("OpenPGL" openpgl_FOUND WITH_CYCLES_PATH_GUIDING)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# OpenColorIO
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_OPENCOLORIO)
|
||||
set(WITH_OPENCOLORIO ON)
|
||||
|
||||
if(NOT USD_OVERRIDE_OPENCOLORIO)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO_ROOT_DIR}/include)
|
||||
set(OPENCOLORIO_LIBRARIES
|
||||
optimized ${OPENCOLORIO_ROOT_DIR}/lib/OpenColorIO.lib
|
||||
optimized ${OPENCOLORIO_ROOT_DIR}/lib/libyaml-cpp.lib
|
||||
optimized ${OPENCOLORIO_ROOT_DIR}/lib/libexpatMD.lib
|
||||
optimized ${OPENCOLORIO_ROOT_DIR}/lib/pystring.lib
|
||||
debug ${OPENCOLORIO_ROOT_DIR}/lib/OpencolorIO_d.lib
|
||||
debug ${OPENCOLORIO_ROOT_DIR}/lib/libyaml-cpp_d.lib
|
||||
debug ${OPENCOLORIO_ROOT_DIR}/lib/libexpatdMD.lib
|
||||
debug ${OPENCOLORIO_ROOT_DIR}/lib/pystring_d.lib
|
||||
)
|
||||
else()
|
||||
find_package(OpenColorIO REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# Boost
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if(EXISTS ${_cycles_lib_dir})
|
||||
if(MSVC)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
else()
|
||||
set(BOOST_LIBRARYDIR ${_cycles_lib_dir}/boost/lib)
|
||||
set(Boost_NO_BOOST_CMAKE ON)
|
||||
set(Boost_NO_SYSTEM_PATHS ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(BOOST_INCLUDE_DIR ${BOOST_ROOT}/include)
|
||||
set(BOOST_VERSION_HEADER ${BOOST_INCLUDE_DIR}/boost/version.hpp)
|
||||
if(EXISTS ${BOOST_VERSION_HEADER})
|
||||
file(STRINGS "${BOOST_VERSION_HEADER}" BOOST_LIB_VERSION REGEX "#define BOOST_LIB_VERSION ")
|
||||
if(BOOST_LIB_VERSION MATCHES "#define BOOST_LIB_VERSION \"([0-9_]+)\"")
|
||||
set(BOOST_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT BOOST_VERSION)
|
||||
message(FATAL_ERROR "Unable to determine Boost version")
|
||||
endif()
|
||||
set(BOOST_POSTFIX "vc142-mt-x64-${BOOST_VERSION}.lib")
|
||||
set(BOOST_DEBUG_POSTFIX "vc142-mt-gd-x64-${BOOST_VERSION}.lib")
|
||||
set(BOOST_LIBRARIES
|
||||
optimized ${BOOST_ROOT}/lib/libboost_date_time-${BOOST_POSTFIX}
|
||||
optimized ${BOOST_ROOT}/lib/libboost_iostreams-${BOOST_POSTFIX}
|
||||
optimized ${BOOST_ROOT}/lib/libboost_filesystem-${BOOST_POSTFIX}
|
||||
optimized ${BOOST_ROOT}/lib/libboost_regex-${BOOST_POSTFIX}
|
||||
optimized ${BOOST_ROOT}/lib/libboost_system-${BOOST_POSTFIX}
|
||||
optimized ${BOOST_ROOT}/lib/libboost_thread-${BOOST_POSTFIX}
|
||||
optimized ${BOOST_ROOT}/lib/libboost_chrono-${BOOST_POSTFIX}
|
||||
debug ${BOOST_ROOT}/lib/libboost_date_time-${BOOST_DEBUG_POSTFIX}
|
||||
debug ${BOOST_ROOT}/lib/libboost_iostreams-${BOOST_DEBUG_POSTFIX}
|
||||
debug ${BOOST_ROOT}/lib/libboost_filesystem-${BOOST_DEBUG_POSTFIX}
|
||||
debug ${BOOST_ROOT}/lib/libboost_regex-${BOOST_DEBUG_POSTFIX}
|
||||
debug ${BOOST_ROOT}/lib/libboost_system-${BOOST_DEBUG_POSTFIX}
|
||||
debug ${BOOST_ROOT}/lib/libboost_thread-${BOOST_DEBUG_POSTFIX}
|
||||
debug ${BOOST_ROOT}/lib/libboost_chrono-${BOOST_DEBUG_POSTFIX}
|
||||
)
|
||||
if(WITH_CYCLES_OSL)
|
||||
set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
|
||||
optimized ${BOOST_ROOT}/lib/libboost_wave-${BOOST_POSTFIX}
|
||||
debug ${BOOST_ROOT}/lib/libboost_wave-${BOOST_DEBUG_POSTFIX})
|
||||
endif()
|
||||
else()
|
||||
set(__boost_packages iostreams filesystem regex system thread date_time)
|
||||
if(WITH_CYCLES_OSL)
|
||||
list(APPEND __boost_packages wave)
|
||||
endif()
|
||||
find_package(Boost 1.48 COMPONENTS ${__boost_packages} REQUIRED)
|
||||
if(NOT Boost_FOUND)
|
||||
# Try to find non-multithreaded if -mt not found, this flag
|
||||
# doesn't matter for us, it has nothing to do with thread
|
||||
# safety, but keep it to not disturb build setups.
|
||||
set(Boost_USE_MULTITHREADED OFF)
|
||||
find_package(Boost 1.48 COMPONENTS ${__boost_packages})
|
||||
endif()
|
||||
unset(__boost_packages)
|
||||
|
||||
set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
|
||||
set(BOOST_LIBRARIES ${Boost_LIBRARIES})
|
||||
set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
|
||||
endif()
|
||||
|
||||
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB ${BOOST_DEFINITIONS}")
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# Embree
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_EMBREE)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(EMBREE_INCLUDE_DIRS ${EMBREE_ROOT_DIR}/include)
|
||||
set(EMBREE_LIBRARIES
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/embree3.lib
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/embree_avx2.lib
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/embree_avx.lib
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/embree_sse42.lib
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/lexers.lib
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/math.lib
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/simd.lib
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/tasking.lib
|
||||
optimized ${EMBREE_ROOT_DIR}/lib/sys.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/embree3_d.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/embree_avx2_d.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/embree_avx_d.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/embree_sse42_d.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/lexers_d.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/math_d.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/simd_d.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/sys_d.lib
|
||||
debug ${EMBREE_ROOT_DIR}/lib/tasking_d.lib
|
||||
)
|
||||
else()
|
||||
find_package(Embree 3.8.0 REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# Logging
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_LOGGING)
|
||||
find_package(Glog REQUIRED)
|
||||
find_package(Gflags REQUIRED)
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# OpenSubdiv
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_OPENSUBDIV)
|
||||
set(WITH_OPENSUBDIV ON)
|
||||
|
||||
if(NOT USD_OVERRIDE_OPENSUBDIV)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(OPENSUBDIV_INCLUDE_DIRS ${OPENSUBDIV_ROOT_DIR}/include)
|
||||
set(OPENSUBDIV_LIBRARIES
|
||||
optimized ${OPENSUBDIV_ROOT_DIR}/lib/osdCPU.lib
|
||||
optimized ${OPENSUBDIV_ROOT_DIR}/lib/osdGPU.lib
|
||||
debug ${OPENSUBDIV_ROOT_DIR}/lib/osdCPU_d.lib
|
||||
debug ${OPENSUBDIV_ROOT_DIR}/lib/osdGPU_d.lib
|
||||
)
|
||||
else()
|
||||
find_package(OpenSubdiv REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# OpenVDB
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_OPENVDB)
|
||||
set(WITH_OPENVDB ON)
|
||||
set(OPENVDB_DEFINITIONS -DNOMINMAX -D_USE_MATH_DEFINES)
|
||||
|
||||
if(NOT USD_OVERRIDE_OPENVDB)
|
||||
find_package(OpenVDB REQUIRED)
|
||||
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(BLOSC_LIBRARY
|
||||
optimized ${BLOSC_ROOT_DIR}/lib/libblosc.lib
|
||||
debug ${BLOSC_ROOT_DIR}/lib/libblosc_d.lib
|
||||
)
|
||||
else()
|
||||
find_package(Blosc REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# NanoVDB
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_NANOVDB)
|
||||
set(WITH_NANOVDB ON)
|
||||
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(NANOVDB_INCLUDE_DIR ${NANOVDB_ROOT_DIR}/include)
|
||||
set(NANOVDB_INCLUDE_DIRS ${NANOVDB_INCLUDE_DIR})
|
||||
else()
|
||||
find_package(NanoVDB REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# OpenImageDenoise
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY AND WITH_CYCLES_OPENIMAGEDENOISE)
|
||||
set(WITH_OPENIMAGEDENOISE ON)
|
||||
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(OPENIMAGEDENOISE_INCLUDE_DIRS ${OPENIMAGEDENOISE_ROOT_DIR}/include)
|
||||
set(OPENIMAGEDENOISE_LIBRARIES
|
||||
optimized ${OPENIMAGEDENOISE_ROOT_DIR}/lib/OpenImageDenoise.lib
|
||||
optimized ${OPENIMAGEDENOISE_ROOT_DIR}/lib/common.lib
|
||||
optimized ${OPENIMAGEDENOISE_ROOT_DIR}/lib/dnnl.lib
|
||||
debug ${OPENIMAGEDENOISE_ROOT_DIR}/lib/OpenImageDenoise_d.lib
|
||||
debug ${OPENIMAGEDENOISE_ROOT_DIR}/lib/common_d.lib
|
||||
debug ${OPENIMAGEDENOISE_ROOT_DIR}/lib/dnnl_d.lib
|
||||
)
|
||||
else()
|
||||
find_package(OpenImageDenoise REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# TBB
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if(NOT USD_OVERRIDE_TBB)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(TBB_INCLUDE_DIRS ${TBB_ROOT_DIR}/include)
|
||||
set(TBB_LIBRARIES
|
||||
optimized ${TBB_ROOT_DIR}/lib/tbb.lib
|
||||
debug ${TBB_ROOT_DIR}/lib/tbb_debug.lib
|
||||
)
|
||||
else()
|
||||
find_package(TBB REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# Epoxy
|
||||
###########################################################################
|
||||
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if((WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI) OR
|
||||
WITH_CYCLES_HYDRA_RENDER_DELEGATE)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(Epoxy_LIBRARIES "${_cycles_lib_dir}/epoxy/lib/epoxy.lib")
|
||||
set(Epoxy_INCLUDE_DIRS "${_cycles_lib_dir}/epoxy/include")
|
||||
else()
|
||||
find_package(Epoxy REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# Alembic
|
||||
###########################################################################
|
||||
|
||||
if(WITH_CYCLES_ALEMBIC)
|
||||
if(CYCLES_STANDALONE_REPOSITORY)
|
||||
if(MSVC AND EXISTS ${_cycles_lib_dir})
|
||||
set(ALEMBIC_INCLUDE_DIRS ${_cycles_lib_dir}/alembic/include)
|
||||
set(ALEMBIC_LIBRARIES
|
||||
optimized ${_cycles_lib_dir}/alembic/lib/Alembic.lib
|
||||
debug ${_cycles_lib_dir}/alembic/lib/Alembic_d.lib)
|
||||
else()
|
||||
find_package(Alembic REQUIRED)
|
||||
endif()
|
||||
|
||||
set(WITH_ALEMBIC ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# System Libraries
|
||||
###########################################################################
|
||||
|
||||
# Detect system libraries again
|
||||
if(EXISTS ${_cycles_lib_dir})
|
||||
unset(CMAKE_IGNORE_PATH)
|
||||
unset(_cycles_lib_dir)
|
||||
endif()
|
||||
|
||||
###########################################################################
|
||||
# SDL
|
||||
###########################################################################
|
||||
|
@ -687,5 +109,3 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
|
|||
set(WITH_CYCLES_DEVICE_ONEAPI OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
unset(_cycles_lib_dir)
|
||||
|
|
|
@ -157,4 +157,47 @@ ccl_device_inline void film_write_data_passes(KernelGlobals kg,
|
|||
#endif
|
||||
}
|
||||
|
||||
ccl_device_inline void film_write_data_passes_background(
|
||||
KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
|
||||
{
|
||||
#ifdef __PASSES__
|
||||
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
|
||||
|
||||
if (!(path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't write data passes for paths that were split off for shadow catchers
|
||||
* to avoid double-counting. */
|
||||
if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int flag = kernel_data.film.pass_flag;
|
||||
|
||||
if (!(flag & PASS_ANY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) {
|
||||
ccl_global float *buffer = film_pass_pixel_render_buffer(kg, state, render_buffer);
|
||||
|
||||
if (INTEGRATOR_STATE(state, path, sample) == 0) {
|
||||
if (flag & PASSMASK(DEPTH)) {
|
||||
film_overwrite_pass_float(buffer + kernel_data.film.pass_depth, 0.0f);
|
||||
}
|
||||
if (flag & PASSMASK(OBJECT_ID)) {
|
||||
film_overwrite_pass_float(buffer + kernel_data.film.pass_object_id, 0.0f);
|
||||
}
|
||||
if (flag & PASSMASK(MATERIAL_ID)) {
|
||||
film_overwrite_pass_float(buffer + kernel_data.film.pass_material_id, 0.0f);
|
||||
}
|
||||
if (flag & PASSMASK(POSITION)) {
|
||||
film_overwrite_pass_float3(buffer + kernel_data.film.pass_position, zero_float3());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/film/data_passes.h"
|
||||
#include "kernel/film/light_passes.h"
|
||||
|
||||
#include "kernel/integrator/guiding.h"
|
||||
|
@ -131,6 +132,7 @@ ccl_device_inline void integrate_background(KernelGlobals kg,
|
|||
|
||||
/* Write to render buffer. */
|
||||
film_write_background(kg, state, L, transparent, is_transparent_background_ray, render_buffer);
|
||||
film_write_data_passes_background(kg, state, render_buffer);
|
||||
}
|
||||
|
||||
ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
|
||||
|
|
|
@ -282,8 +282,12 @@ class NLA_OT_bake(Operator):
|
|||
|
||||
def invoke(self, context, _event):
|
||||
scene = context.scene
|
||||
self.frame_start = scene.frame_start
|
||||
self.frame_end = scene.frame_end
|
||||
if scene.use_preview_range:
|
||||
self.frame_start = scene.frame_preview_start
|
||||
self.frame_end = scene.frame_preview_end
|
||||
else:
|
||||
self.frame_start = scene.frame_start
|
||||
self.frame_end = scene.frame_end
|
||||
self.bake_types = {'POSE'} if context.mode == 'POSE' else {'OBJECT'}
|
||||
|
||||
wm = context.window_manager
|
||||
|
|
|
@ -2073,6 +2073,7 @@ class _defs_gpencil_paint:
|
|||
def draw_settings(_context, layout, tool):
|
||||
props = tool.operator_properties("gpencil.interpolate")
|
||||
layout.prop(props, "layers")
|
||||
layout.prop(props, "exclude_breakdowns")
|
||||
layout.prop(props, "flip")
|
||||
layout.prop(props, "smooth_factor")
|
||||
layout.prop(props, "smooth_steps")
|
||||
|
@ -2256,6 +2257,7 @@ class _defs_gpencil_edit:
|
|||
props = tool.operator_properties("gpencil.interpolate")
|
||||
layout.prop(props, "layers")
|
||||
layout.prop(props, "interpolate_selected_only")
|
||||
layout.prop(props, "exclude_breakdowns")
|
||||
layout.prop(props, "flip")
|
||||
layout.prop(props, "smooth_factor")
|
||||
layout.prop(props, "smooth_steps")
|
||||
|
|
|
@ -132,7 +132,8 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
|
|||
/**
|
||||
* Sets each output array element to the edge index if it is a real edge, or -1.
|
||||
*/
|
||||
void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh,
|
||||
void BKE_mesh_looptri_get_real_edges(const struct MEdge *edges,
|
||||
const struct MLoop *loops,
|
||||
const struct MLoopTri *looptri,
|
||||
int r_edges[3]);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace blender::meshintersect {
|
|||
* It is allowed for the pointers to be null, meaning the transformation is the identity.
|
||||
* \param material_remaps: An array of maps from material slot numbers in the corresponding mesh
|
||||
* to the material slot in the first mesh. It is OK for material_remaps or any of its constituent
|
||||
* arrays to be empty.
|
||||
* arrays to be empty. A -1 value means that the original index should be used with no mapping.
|
||||
* \param r_intersecting_edges: Array to store indices of edges on the resulting mesh in. These
|
||||
* 'new' edges are the result of the intersections.
|
||||
*/
|
||||
|
|
|
@ -351,6 +351,7 @@ namespace blender::bke::mesh_topology {
|
|||
Array<int> build_loop_to_poly_map(Span<MPoly> polys, int loops_num);
|
||||
|
||||
Array<Vector<int>> build_vert_to_edge_map(Span<MEdge> edges, int verts_num);
|
||||
Array<Vector<int>> build_vert_to_poly_map(Span<MPoly> polys, Span<MLoop> loops, int verts_num);
|
||||
Array<Vector<int>> build_vert_to_loop_map(Span<MLoop> loops, int verts_num);
|
||||
Array<Vector<int>> build_edge_to_loop_map(Span<MLoop> loops, int edges_num);
|
||||
Vector<Vector<int>> build_edge_to_loop_map_resizable(Span<MLoop> loops, int edges_num);
|
||||
|
|
|
@ -156,15 +156,8 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float
|
|||
/**
|
||||
* Find per-corner coordinate with given per-face UV coord.
|
||||
*/
|
||||
int mdisp_rot_face_to_crn(struct MVert *mvert,
|
||||
struct MPoly *mpoly,
|
||||
struct MLoop *mloop,
|
||||
const struct MLoopTri *lt,
|
||||
int face_side,
|
||||
float u,
|
||||
float v,
|
||||
float *x,
|
||||
float *y);
|
||||
int mdisp_rot_face_to_crn(
|
||||
struct MPoly *mpoly, int face_side, float u, float v, float *x, float *y);
|
||||
|
||||
/* Reshaping, define in multires_reshape.c */
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
|
||||
namespace blender::bke::uv_islands {
|
||||
|
||||
struct MeshEdge;
|
||||
|
|
|
@ -1122,7 +1122,8 @@ static bool collection_object_remove(Main *bmain,
|
|||
id_us_min(&ob->id);
|
||||
}
|
||||
|
||||
collection_tag_update_parent_recursive(bmain, collection, ID_RECALC_COPY_ON_WRITE);
|
||||
collection_tag_update_parent_recursive(
|
||||
bmain, collection, ID_RECALC_COPY_ON_WRITE | ID_RECALC_GEOMETRY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1490,13 +1490,13 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v)
|
|||
return -1;
|
||||
}
|
||||
|
||||
void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3])
|
||||
void BKE_mesh_looptri_get_real_edges(const MEdge *edges,
|
||||
const MLoop *loops,
|
||||
const MLoopTri *tri,
|
||||
int r_edges[3])
|
||||
{
|
||||
const Span<MEdge> edges = mesh->edges();
|
||||
const Span<MLoop> loops = mesh->loops();
|
||||
|
||||
for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
|
||||
const MLoop *l1 = &loops[looptri->tri[i]], *l2 = &loops[looptri->tri[i_next]];
|
||||
const MLoop *l1 = &loops[tri->tri[i]], *l2 = &loops[tri->tri[i_next]];
|
||||
const MEdge *e = &edges[l1->e];
|
||||
|
||||
bool is_real = (l1->v == e->v1 && l2->v == e->v2) || (l1->v == e->v2 && l2->v == e->v1);
|
||||
|
|
|
@ -430,12 +430,14 @@ static void copy_poly_attributes(Mesh *dest_mesh,
|
|||
const VArray<int> src_material_indices = orig_me->attributes().lookup_or_default<int>(
|
||||
"material_index", ATTR_DOMAIN_FACE, 0);
|
||||
const int src_index = src_material_indices[index_in_orig_me];
|
||||
if (material_remap.size() > 0 && material_remap.index_range().contains(src_index)) {
|
||||
dst_material_indices[mp_index] = material_remap[src_index];
|
||||
if (material_remap.index_range().contains(src_index)) {
|
||||
const int remapped_index = material_remap[src_index];
|
||||
dst_material_indices[mp_index] = remapped_index >= 0 ? remapped_index : src_index;
|
||||
}
|
||||
else {
|
||||
dst_material_indices[mp_index] = src_index;
|
||||
}
|
||||
BLI_assert(dst_material_indices[mp_index] >= 0);
|
||||
}
|
||||
|
||||
/* Similar to copy_vert_attributes but for edge attributes. */
|
||||
|
|
|
@ -577,6 +577,20 @@ Array<Vector<int>> build_vert_to_edge_map(const Span<MEdge> edges, const int ver
|
|||
return map;
|
||||
}
|
||||
|
||||
Array<Vector<int>> build_vert_to_poly_map(const Span<MPoly> polys,
|
||||
const Span<MLoop> loops,
|
||||
int verts_num)
|
||||
{
|
||||
Array<Vector<int>> map(verts_num);
|
||||
for (const int64_t i : polys.index_range()) {
|
||||
const MPoly &poly = polys[i];
|
||||
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
|
||||
map[loop.v].append(int(i));
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
Array<Vector<int>> build_vert_to_loop_map(const Span<MLoop> loops, const int verts_num)
|
||||
{
|
||||
Array<Vector<int>> map(verts_num);
|
||||
|
|
|
@ -260,45 +260,32 @@ void BKE_mesh_calc_poly_normal_coords(const MPoly *mpoly,
|
|||
}
|
||||
}
|
||||
|
||||
struct MeshCalcNormalsData_Poly {
|
||||
const MVert *mvert;
|
||||
const MLoop *mloop;
|
||||
const MPoly *mpoly;
|
||||
|
||||
/** Polygon normal output. */
|
||||
float (*pnors)[3];
|
||||
};
|
||||
|
||||
static void mesh_calc_normals_poly_fn(void *__restrict userdata,
|
||||
const int pidx,
|
||||
const TaskParallelTLS *__restrict /*tls*/)
|
||||
static void calculate_normals_poly(const Span<MVert> verts,
|
||||
const Span<MPoly> polys,
|
||||
const Span<MLoop> loops,
|
||||
MutableSpan<float3> poly_normals)
|
||||
{
|
||||
const MeshCalcNormalsData_Poly *data = (MeshCalcNormalsData_Poly *)userdata;
|
||||
const MPoly *mp = &data->mpoly[pidx];
|
||||
BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mvert, data->pnors[pidx]);
|
||||
using namespace blender;
|
||||
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int poly_i : range) {
|
||||
const MPoly &poly = polys[poly_i];
|
||||
BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], verts.data(), poly_normals[poly_i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BKE_mesh_calc_normals_poly(const MVert *mvert,
|
||||
int /*mvert_len*/,
|
||||
const int mvert_len,
|
||||
const MLoop *mloop,
|
||||
int /*mloop_len*/,
|
||||
const int mloop_len,
|
||||
const MPoly *mpoly,
|
||||
int mpoly_len,
|
||||
float (*r_poly_normals)[3])
|
||||
{
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = 1024;
|
||||
|
||||
BLI_assert((r_poly_normals != nullptr) || (mpoly_len == 0));
|
||||
|
||||
MeshCalcNormalsData_Poly data = {};
|
||||
data.mpoly = mpoly;
|
||||
data.mloop = mloop;
|
||||
data.mvert = mvert;
|
||||
data.pnors = r_poly_normals;
|
||||
|
||||
BLI_task_parallel_range(0, mpoly_len, &data, mesh_calc_normals_poly_fn, &settings);
|
||||
calculate_normals_poly({mvert, mvert_len},
|
||||
{mpoly, mpoly_len},
|
||||
{mloop, mloop_len},
|
||||
{reinterpret_cast<float3 *>(r_poly_normals), mpoly_len});
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -310,123 +297,110 @@ void BKE_mesh_calc_normals_poly(const MVert *mvert,
|
|||
* meshes can slow down high-poly meshes. For details on performance, see D11993.
|
||||
* \{ */
|
||||
|
||||
struct MeshCalcNormalsData_PolyAndVertex {
|
||||
const MVert *mvert;
|
||||
const MLoop *mloop;
|
||||
const MPoly *mpoly;
|
||||
|
||||
/** Polygon normal output. */
|
||||
float (*pnors)[3];
|
||||
/** Vertex normal output. */
|
||||
float (*vnors)[3];
|
||||
};
|
||||
|
||||
static void mesh_calc_normals_poly_and_vertex_accum_fn(void *__restrict userdata,
|
||||
const int pidx,
|
||||
const TaskParallelTLS *__restrict /*tls*/)
|
||||
static void calculate_normals_poly_and_vert(const Span<MVert> verts,
|
||||
const Span<MPoly> polys,
|
||||
const Span<MLoop> loops,
|
||||
MutableSpan<float3> poly_normals,
|
||||
MutableSpan<float3> vert_normals)
|
||||
{
|
||||
const MeshCalcNormalsData_PolyAndVertex *data = (MeshCalcNormalsData_PolyAndVertex *)userdata;
|
||||
const MPoly *mp = &data->mpoly[pidx];
|
||||
const MLoop *ml = &data->mloop[mp->loopstart];
|
||||
const MVert *mverts = data->mvert;
|
||||
float(*vnors)[3] = data->vnors;
|
||||
using namespace blender;
|
||||
|
||||
float pnor_temp[3];
|
||||
float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
|
||||
|
||||
const int i_end = mp->totloop - 1;
|
||||
|
||||
/* Polygon Normal and edge-vector. */
|
||||
/* Inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors. */
|
||||
/* Zero the vertex normal array for accumulation. */
|
||||
{
|
||||
zero_v3(pnor);
|
||||
/* Newell's Method */
|
||||
const float *v_curr = mverts[ml[i_end].v].co;
|
||||
for (int i_next = 0; i_next <= i_end; i_next++) {
|
||||
const float *v_next = mverts[ml[i_next].v].co;
|
||||
add_newell_cross_v3_v3v3(pnor, v_curr, v_next);
|
||||
v_curr = v_next;
|
||||
}
|
||||
if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
|
||||
pnor[2] = 1.0f; /* Other axes set to zero. */
|
||||
}
|
||||
memset(vert_normals.data(), 0, vert_normals.as_span().size_in_bytes());
|
||||
}
|
||||
|
||||
/* Accumulate angle weighted face normal into the vertex normal. */
|
||||
/* Inline version of #accumulate_vertex_normals_poly_v3. */
|
||||
/* Compute poly normals, accumulating them into vertex normals. */
|
||||
{
|
||||
float edvec_prev[3], edvec_next[3], edvec_end[3];
|
||||
const float *v_curr = mverts[ml[i_end].v].co;
|
||||
sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr);
|
||||
normalize_v3(edvec_prev);
|
||||
copy_v3_v3(edvec_end, edvec_prev);
|
||||
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int poly_i : range) {
|
||||
const MPoly &poly = polys[poly_i];
|
||||
const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
|
||||
|
||||
for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) {
|
||||
const float *v_next = mverts[ml[i_next].v].co;
|
||||
float3 &pnor = poly_normals[poly_i];
|
||||
|
||||
/* Skip an extra normalization by reusing the first calculated edge. */
|
||||
if (i_next != i_end) {
|
||||
sub_v3_v3v3(edvec_next, v_curr, v_next);
|
||||
normalize_v3(edvec_next);
|
||||
const int i_end = poly.totloop - 1;
|
||||
|
||||
/* Polygon Normal and edge-vector. */
|
||||
/* Inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors. */
|
||||
{
|
||||
zero_v3(pnor);
|
||||
/* Newell's Method */
|
||||
const float *v_curr = verts[poly_loops[i_end].v].co;
|
||||
for (int i_next = 0; i_next <= i_end; i_next++) {
|
||||
const float *v_next = verts[poly_loops[i_next].v].co;
|
||||
add_newell_cross_v3_v3v3(pnor, v_curr, v_next);
|
||||
v_curr = v_next;
|
||||
}
|
||||
if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
|
||||
pnor[2] = 1.0f; /* Other axes set to zero. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Accumulate angle weighted face normal into the vertex normal. */
|
||||
/* Inline version of #accumulate_vertex_normals_poly_v3. */
|
||||
{
|
||||
float edvec_prev[3], edvec_next[3], edvec_end[3];
|
||||
const float *v_curr = verts[poly_loops[i_end].v].co;
|
||||
sub_v3_v3v3(edvec_prev, verts[poly_loops[i_end - 1].v].co, v_curr);
|
||||
normalize_v3(edvec_prev);
|
||||
copy_v3_v3(edvec_end, edvec_prev);
|
||||
|
||||
for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) {
|
||||
const float *v_next = verts[poly_loops[i_next].v].co;
|
||||
|
||||
/* Skip an extra normalization by reusing the first calculated edge. */
|
||||
if (i_next != i_end) {
|
||||
sub_v3_v3v3(edvec_next, v_curr, v_next);
|
||||
normalize_v3(edvec_next);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(edvec_next, edvec_end);
|
||||
}
|
||||
|
||||
/* Calculate angle between the two poly edges incident on this vertex. */
|
||||
const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next));
|
||||
const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac};
|
||||
|
||||
float *vnor = vert_normals[poly_loops[i_curr].v];
|
||||
add_v3_v3_atomic(vnor, vnor_add);
|
||||
v_curr = v_next;
|
||||
copy_v3_v3(edvec_prev, edvec_next);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(edvec_next, edvec_end);
|
||||
}
|
||||
|
||||
/* Calculate angle between the two poly edges incident on this vertex. */
|
||||
const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next));
|
||||
const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac};
|
||||
|
||||
add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add);
|
||||
v_curr = v_next;
|
||||
copy_v3_v3(edvec_prev, edvec_next);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void mesh_calc_normals_poly_and_vertex_finalize_fn(
|
||||
void *__restrict userdata, const int vidx, const TaskParallelTLS *__restrict /*tls*/)
|
||||
{
|
||||
MeshCalcNormalsData_PolyAndVertex *data = (MeshCalcNormalsData_PolyAndVertex *)userdata;
|
||||
/* Normalize and validate computed vertex normals. */
|
||||
{
|
||||
threading::parallel_for(verts.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int vert_i : range) {
|
||||
float *no = vert_normals[vert_i];
|
||||
|
||||
const MVert *mv = &data->mvert[vidx];
|
||||
float *no = data->vnors[vidx];
|
||||
|
||||
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
|
||||
/* Following Mesh convention; we use vertex coordinate itself for normal in this case. */
|
||||
normalize_v3_v3(no, mv->co);
|
||||
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
|
||||
/* Following Mesh convention; we use vertex coordinate itself for normal in this case. */
|
||||
normalize_v3_v3(no, verts[vert_i].co);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert,
|
||||
const int mvert_len,
|
||||
const MLoop *mloop,
|
||||
const int /*mloop_len*/,
|
||||
const int mloop_len,
|
||||
const MPoly *mpoly,
|
||||
const int mpoly_len,
|
||||
float (*r_poly_normals)[3],
|
||||
float (*r_vert_normals)[3])
|
||||
{
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = 1024;
|
||||
|
||||
memset(r_vert_normals, 0, sizeof(*r_vert_normals) * size_t(mvert_len));
|
||||
|
||||
MeshCalcNormalsData_PolyAndVertex data = {};
|
||||
data.mpoly = mpoly;
|
||||
data.mloop = mloop;
|
||||
data.mvert = mvert;
|
||||
data.pnors = r_poly_normals;
|
||||
data.vnors = r_vert_normals;
|
||||
|
||||
/* Compute poly normals, accumulating them into vertex normals. */
|
||||
BLI_task_parallel_range(
|
||||
0, mpoly_len, &data, mesh_calc_normals_poly_and_vertex_accum_fn, &settings);
|
||||
|
||||
/* Normalize and validate computed vertex normals. */
|
||||
BLI_task_parallel_range(
|
||||
0, mvert_len, &data, mesh_calc_normals_poly_and_vertex_finalize_fn, &settings);
|
||||
calculate_normals_poly_and_vert({mvert, mvert_len},
|
||||
{mpoly, mpoly_len},
|
||||
{mloop, mloop_len},
|
||||
{reinterpret_cast<float3 *>(r_poly_normals), mpoly_len},
|
||||
{reinterpret_cast<float3 *>(r_vert_normals), mvert_len});
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -288,7 +288,7 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source)
|
|||
{
|
||||
BVHTreeFromMesh bvhtree = {nullptr};
|
||||
BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2);
|
||||
const MVert *target_verts = (const MVert *)CustomData_get_layer(&target->vdata, CD_MVERT);
|
||||
const Span<MVert> target_verts = target->verts();
|
||||
const float *source_mask = (const float *)CustomData_get_layer(&source->vdata, CD_PAINT_MASK);
|
||||
if (source_mask == nullptr) {
|
||||
return;
|
||||
|
@ -305,13 +305,11 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source)
|
|||
|
||||
blender::threading::parallel_for(IndexRange(target->totvert), 4096, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
float from_co[3];
|
||||
BVHTreeNearest nearest;
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = FLT_MAX;
|
||||
copy_v3_v3(from_co, target_verts[i].co);
|
||||
BLI_bvhtree_find_nearest(
|
||||
bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
|
||||
bvhtree.tree, target_verts[i].co, &nearest, bvhtree.nearest_callback, &bvhtree);
|
||||
if (nearest.index != -1) {
|
||||
target_mask[i] = source_mask[nearest.index];
|
||||
}
|
||||
|
@ -326,9 +324,9 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source)
|
|||
using namespace blender::bke;
|
||||
const AttributeAccessor src_attributes = source->attributes();
|
||||
MutableAttributeAccessor dst_attributes = target->attributes_for_write();
|
||||
const MPoly *target_polys = (const MPoly *)CustomData_get_layer(&target->pdata, CD_MPOLY);
|
||||
const MVert *target_verts = (const MVert *)CustomData_get_layer(&target->vdata, CD_MVERT);
|
||||
const MLoop *target_loops = (const MLoop *)CustomData_get_layer(&target->ldata, CD_MLOOP);
|
||||
const Span<MVert> target_verts = target->verts();
|
||||
const Span<MPoly> target_polys = target->polys();
|
||||
const Span<MLoop> target_loops = target->loops();
|
||||
|
||||
const VArray<int> src_face_sets = src_attributes.lookup<int>(".sculpt_face_set",
|
||||
ATTR_DOMAIN_FACE);
|
||||
|
@ -354,8 +352,9 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source)
|
|||
BVHTreeNearest nearest;
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = FLT_MAX;
|
||||
const MPoly *mpoly = &target_polys[i];
|
||||
BKE_mesh_calc_poly_center(mpoly, &target_loops[mpoly->loopstart], target_verts, from_co);
|
||||
const MPoly &poly = target_polys[i];
|
||||
BKE_mesh_calc_poly_center(
|
||||
&poly, &target_loops[poly.loopstart], target_verts.data(), from_co);
|
||||
BLI_bvhtree_find_nearest(
|
||||
bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
|
||||
if (nearest.index != -1) {
|
||||
|
@ -403,7 +402,7 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source)
|
|||
size_t data_size = CustomData_sizeof(layer->type);
|
||||
void *target_data = target_cdata->layers[layer_i].data;
|
||||
void *source_data = layer->data;
|
||||
MVert *target_verts = (MVert *)CustomData_get_layer(&target->vdata, CD_MVERT);
|
||||
const Span<MVert> target_verts = target->verts();
|
||||
|
||||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
blender::threading::parallel_for(
|
||||
|
|
|
@ -1522,15 +1522,8 @@ void multiresModifier_ensure_external_read(struct Mesh *mesh, const MultiresModi
|
|||
|
||||
/***************** Multires interpolation stuff *****************/
|
||||
|
||||
int mdisp_rot_face_to_crn(struct MVert * /*mvert*/,
|
||||
struct MPoly *mpoly,
|
||||
struct MLoop * /*mloop*/,
|
||||
const struct MLoopTri * /*lt*/,
|
||||
const int face_side,
|
||||
const float u,
|
||||
const float v,
|
||||
float *x,
|
||||
float *y)
|
||||
int mdisp_rot_face_to_crn(
|
||||
MPoly *mpoly, const int face_side, const float u, const float v, float *x, float *y)
|
||||
{
|
||||
const float offset = face_side * 0.5f - 0.5f;
|
||||
int S = 0;
|
||||
|
|
|
@ -963,11 +963,9 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract(
|
|||
* Checks the orientation of the loops to flip the x and y axis when extracting the grid if
|
||||
* necessary.
|
||||
*/
|
||||
static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x)
|
||||
static bool multires_unsubdivide_flip_grid_x_axis(
|
||||
const MPoly *polys, const MLoop *loops, int poly, int loop, int v_x)
|
||||
{
|
||||
const MPoly *polys = BKE_mesh_polys(mesh);
|
||||
const MLoop *loops = BKE_mesh_loops(mesh);
|
||||
|
||||
const MPoly *p = &polys[poly];
|
||||
|
||||
const MLoop *l_first = &loops[p->loopstart];
|
||||
|
@ -1037,6 +1035,9 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte
|
|||
const int base_l_offset = CustomData_get_n_offset(
|
||||
&bm_base_mesh->ldata, CD_PROP_INT32, base_l_layer_index);
|
||||
|
||||
const MPoly *polys = BKE_mesh_polys(base_mesh);
|
||||
const MLoop *loops = BKE_mesh_loops(base_mesh);
|
||||
|
||||
/* Main loop for extracting the grids. Iterates over the base mesh vertices. */
|
||||
BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) {
|
||||
|
||||
|
@ -1074,7 +1075,7 @@ static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *conte
|
|||
/* Check the orientation of the loops in case that is needed to flip the x and y axis
|
||||
* when extracting the grid. */
|
||||
const bool flip_grid = multires_unsubdivide_flip_grid_x_axis(
|
||||
base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index);
|
||||
polys, loops, base_mesh_face_index, base_mesh_loop_index, corner_x_index);
|
||||
|
||||
/* Extract the grid for that loop. */
|
||||
context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index;
|
||||
|
|
|
@ -3765,7 +3765,6 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh)
|
|||
}
|
||||
case PBVH_GRIDS: {
|
||||
const MPoly *mp = BKE_mesh_polys(mesh);
|
||||
const MLoop *mloop = BKE_mesh_loops(mesh);
|
||||
CCGKey key = pbvh->gridkey;
|
||||
|
||||
bool *hide_poly = (bool *)CustomData_get_layer_named(
|
||||
|
@ -3773,10 +3772,9 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh)
|
|||
|
||||
bool delete_hide_poly = true;
|
||||
for (int face_index = 0; face_index < mesh->totpoly; face_index++, mp++) {
|
||||
const MLoop *ml = mloop + mp->loopstart;
|
||||
bool hidden = false;
|
||||
|
||||
for (int loop_index = 0; !hidden && loop_index < mp->totloop; loop_index++, ml++) {
|
||||
for (int loop_index = 0; !hidden && loop_index < mp->totloop; loop_index++) {
|
||||
int grid_index = mp->loopstart + loop_index;
|
||||
|
||||
if (pbvh->grid_hidden[grid_index] &&
|
||||
|
|
|
@ -239,7 +239,7 @@ static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(Mesh *mesh)
|
|||
|
||||
for (int i = 0; i < totlooptri; i++) {
|
||||
int edges[3];
|
||||
BKE_mesh_looptri_get_real_edges(mesh, &mlooptri[i], edges);
|
||||
BKE_mesh_looptri_get_real_edges(medge, mloop, &mlooptri[i], edges);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (edges[j] >= 0 && edge_mode[edges[j]]) {
|
||||
|
@ -1049,7 +1049,7 @@ static void mesh_looptri_target_project(void *userdata,
|
|||
const BLI_bitmap *is_boundary = tree->boundary->edge_is_boundary;
|
||||
int edges[3];
|
||||
|
||||
BKE_mesh_looptri_get_real_edges(tree->mesh, lt, edges);
|
||||
BKE_mesh_looptri_get_real_edges(data->edge, data->loop, lt, edges);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (edges[i] >= 0 && BLI_BITMAP_TEST(is_boundary, edges[i])) {
|
||||
|
|
|
@ -67,6 +67,9 @@ BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
|
|||
|
||||
typedef struct SubdivForeachTaskContext {
|
||||
const Mesh *coarse_mesh;
|
||||
const MEdge *coarse_edges;
|
||||
const MPoly *coarse_polys;
|
||||
const MLoop *coarse_loops;
|
||||
const SubdivToMeshSettings *settings;
|
||||
/* Callbacks. */
|
||||
const SubdivForeachContext *foreach_context;
|
||||
|
@ -158,16 +161,14 @@ static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx)
|
|||
const int num_inner_vertices_per_noquad_patch = (no_quad_patch_resolution - 2) *
|
||||
(no_quad_patch_resolution - 2);
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
ctx->num_subdiv_vertices = coarse_mesh->totvert;
|
||||
ctx->num_subdiv_edges = coarse_mesh->totedge * (num_subdiv_vertices_per_coarse_edge + 1);
|
||||
/* Calculate extra vertices and edges created by non-loose geometry. */
|
||||
for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
const MPoly *coarse_poly = &ctx->coarse_polys[poly_index];
|
||||
const int num_ptex_faces_per_poly = num_ptex_faces_per_poly_get(coarse_poly);
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
||||
const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MLoop *loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
const bool is_edge_used = BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, loop->e);
|
||||
/* Edges which aren't counted yet. */
|
||||
if (!is_edge_used) {
|
||||
|
@ -225,12 +226,11 @@ static void subdiv_foreach_ctx_init_offsets(SubdivForeachTaskContext *ctx)
|
|||
ctx->edge_inner_offset = ctx->edge_boundary_offset +
|
||||
coarse_mesh->totedge * num_subdiv_edges_per_coarse_edge;
|
||||
/* "Indexed" offsets. */
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
int vertex_offset = 0;
|
||||
int edge_offset = 0;
|
||||
int polygon_offset = 0;
|
||||
for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
const MPoly *coarse_poly = &ctx->coarse_polys[poly_index];
|
||||
const int num_ptex_faces_per_poly = num_ptex_faces_per_poly_get(coarse_poly);
|
||||
ctx->subdiv_vertex_offset[poly_index] = vertex_offset;
|
||||
ctx->subdiv_edge_offset[poly_index] = edge_offset;
|
||||
|
@ -300,13 +300,10 @@ static void subdiv_foreach_corner_vertices_regular_do(
|
|||
bool check_usage)
|
||||
{
|
||||
const float weights[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const int coarse_poly_index = coarse_poly - coarse_mpoly;
|
||||
const int coarse_poly_index = coarse_poly - ctx->coarse_polys;
|
||||
const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
||||
const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MLoop *coarse_loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
if (check_usage &&
|
||||
BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, coarse_loop->v)) {
|
||||
continue;
|
||||
|
@ -342,13 +339,10 @@ static void subdiv_foreach_corner_vertices_special_do(
|
|||
SubdivForeachVertexFromCornerCb vertex_corner,
|
||||
bool check_usage)
|
||||
{
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const int coarse_poly_index = coarse_poly - coarse_mpoly;
|
||||
const int coarse_poly_index = coarse_poly - ctx->coarse_polys;
|
||||
int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++, ptex_face_index++) {
|
||||
const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MLoop *coarse_loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
if (check_usage &&
|
||||
BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, coarse_loop->v)) {
|
||||
continue;
|
||||
|
@ -409,9 +403,8 @@ static void subdiv_foreach_every_corner_vertices(SubdivForeachTaskContext *ctx,
|
|||
return;
|
||||
}
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
const MPoly *coarse_poly = &ctx->coarse_polys[poly_index];
|
||||
if (coarse_poly->totloop == 4) {
|
||||
subdiv_foreach_every_corner_vertices_regular(ctx, tls, coarse_poly);
|
||||
}
|
||||
|
@ -433,21 +426,16 @@ static void subdiv_foreach_edge_vertices_regular_do(SubdivForeachTaskContext *ct
|
|||
const int resolution_1 = resolution - 1;
|
||||
const float inv_resolution_1 = 1.0f / (float)resolution_1;
|
||||
const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MEdge *coarse_medge = BKE_mesh_edges(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const int coarse_poly_index = coarse_poly - coarse_mpoly;
|
||||
const int poly_index = coarse_poly - coarse_mpoly;
|
||||
const int ptex_face_index = ctx->face_ptex_offset[poly_index];
|
||||
const int coarse_poly_index = coarse_poly - ctx->coarse_polys;
|
||||
const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
||||
const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MLoop *coarse_loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
const int coarse_edge_index = coarse_loop->e;
|
||||
if (check_usage &&
|
||||
BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, coarse_edge_index)) {
|
||||
continue;
|
||||
}
|
||||
const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_edge_index];
|
||||
const bool flip = (coarse_edge->v2 == coarse_loop->v);
|
||||
int subdiv_vertex_index = ctx->vertices_edge_offset +
|
||||
coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
|
||||
|
@ -500,22 +488,17 @@ static void subdiv_foreach_edge_vertices_special_do(SubdivForeachTaskContext *ct
|
|||
const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
|
||||
const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1);
|
||||
const float inv_ptex_resolution_1 = 1.0f / (float)(num_vertices_per_ptex_edge - 1);
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MEdge *coarse_medge = BKE_mesh_edges(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const int coarse_poly_index = coarse_poly - coarse_mpoly;
|
||||
const int poly_index = coarse_poly - coarse_mpoly;
|
||||
const int ptex_face_start_index = ctx->face_ptex_offset[poly_index];
|
||||
const int coarse_poly_index = coarse_poly - ctx->coarse_polys;
|
||||
const int ptex_face_start_index = ctx->face_ptex_offset[coarse_poly_index];
|
||||
int ptex_face_index = ptex_face_start_index;
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++, ptex_face_index++) {
|
||||
const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MLoop *coarse_loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
const int coarse_edge_index = coarse_loop->e;
|
||||
if (check_usage &&
|
||||
BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, coarse_edge_index)) {
|
||||
continue;
|
||||
}
|
||||
const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_edge_index];
|
||||
const bool flip = (coarse_edge->v2 == coarse_loop->v);
|
||||
int subdiv_vertex_index = ctx->vertices_edge_offset +
|
||||
coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
|
||||
|
@ -597,9 +580,8 @@ static void subdiv_foreach_every_edge_vertices(SubdivForeachTaskContext *ctx, vo
|
|||
return;
|
||||
}
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
const MPoly *coarse_poly = &ctx->coarse_polys[poly_index];
|
||||
if (coarse_poly->totloop == 4) {
|
||||
subdiv_foreach_every_edge_vertices_regular(ctx, tls, coarse_poly);
|
||||
}
|
||||
|
@ -617,9 +599,7 @@ static void subdiv_foreach_inner_vertices_regular(SubdivForeachTaskContext *ctx,
|
|||
{
|
||||
const int resolution = ctx->settings->resolution;
|
||||
const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const int coarse_poly_index = coarse_poly - coarse_mpoly;
|
||||
const int coarse_poly_index = coarse_poly - ctx->coarse_polys;
|
||||
const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
|
||||
const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
|
||||
int subdiv_vertex_index = ctx->vertices_inner_offset + start_vertex_index;
|
||||
|
@ -646,9 +626,7 @@ static void subdiv_foreach_inner_vertices_special(SubdivForeachTaskContext *ctx,
|
|||
const int resolution = ctx->settings->resolution;
|
||||
const int ptex_face_resolution = ptex_face_resolution_get(coarse_poly, resolution);
|
||||
const float inv_ptex_face_resolution_1 = 1.0f / (float)(ptex_face_resolution - 1);
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const int coarse_poly_index = coarse_poly - coarse_mpoly;
|
||||
const int coarse_poly_index = coarse_poly - ctx->coarse_polys;
|
||||
int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
|
||||
const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
|
||||
int subdiv_vertex_index = ctx->vertices_inner_offset + start_vertex_index;
|
||||
|
@ -694,11 +672,8 @@ static void subdiv_foreach_inner_vertices(SubdivForeachTaskContext *ctx,
|
|||
/* Traverse all vertices which are emitted from given coarse polygon. */
|
||||
static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx, void *tls, const int poly_index)
|
||||
{
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
if (ctx->foreach_context->vertex_inner != NULL) {
|
||||
subdiv_foreach_inner_vertices(ctx, tls, coarse_poly);
|
||||
subdiv_foreach_inner_vertices(ctx, tls, &ctx->coarse_polys[poly_index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -778,11 +753,7 @@ static void subdiv_foreach_edges_all_patches_regular(SubdivForeachTaskContext *c
|
|||
void *tls,
|
||||
const MPoly *coarse_poly)
|
||||
{
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MEdge *coarse_medge = BKE_mesh_edges(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const int poly_index = coarse_poly - coarse_mpoly;
|
||||
const int poly_index = coarse_poly - ctx->coarse_polys;
|
||||
const int resolution = ctx->settings->resolution;
|
||||
const int start_vertex_index = ctx->vertices_inner_offset +
|
||||
ctx->subdiv_vertex_offset[poly_index];
|
||||
|
@ -820,8 +791,8 @@ static void subdiv_foreach_edges_all_patches_regular(SubdivForeachTaskContext *c
|
|||
}
|
||||
/* Connect inner part of patch to boundary. */
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
||||
const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
|
||||
const MLoop *coarse_loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_loop->e];
|
||||
const int start_edge_vertex = ctx->vertices_edge_offset +
|
||||
coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
|
||||
const bool flip = (coarse_edge->v2 == coarse_loop->v);
|
||||
|
@ -859,11 +830,7 @@ static void subdiv_foreach_edges_all_patches_special(SubdivForeachTaskContext *c
|
|||
void *tls,
|
||||
const MPoly *coarse_poly)
|
||||
{
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MEdge *coarse_medge = BKE_mesh_edges(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const int poly_index = coarse_poly - coarse_mpoly;
|
||||
const int poly_index = coarse_poly - ctx->coarse_polys;
|
||||
const int resolution = ctx->settings->resolution;
|
||||
const int ptex_face_resolution = ptex_face_resolution_get(coarse_poly, resolution);
|
||||
const int ptex_face_inner_resolution = ptex_face_resolution - 2;
|
||||
|
@ -932,11 +899,12 @@ static void subdiv_foreach_edges_all_patches_special(SubdivForeachTaskContext *c
|
|||
}
|
||||
}
|
||||
/* Connect inner path of patch to boundary. */
|
||||
const MLoop *prev_coarse_loop = &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
|
||||
const MLoop *prev_coarse_loop =
|
||||
&ctx->coarse_loops[coarse_poly->loopstart + coarse_poly->totloop - 1];
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
||||
const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MLoop *coarse_loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
{
|
||||
const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_loop->e];
|
||||
const int start_edge_vertex = ctx->vertices_edge_offset +
|
||||
coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
|
||||
const bool flip = (coarse_edge->v2 == coarse_loop->v);
|
||||
|
@ -956,7 +924,7 @@ static void subdiv_foreach_edges_all_patches_special(SubdivForeachTaskContext *c
|
|||
}
|
||||
}
|
||||
if (ptex_face_resolution >= 3) {
|
||||
const MEdge *coarse_edge = &coarse_medge[prev_coarse_loop->e];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[prev_coarse_loop->e];
|
||||
const int start_edge_vertex = ctx->vertices_edge_offset +
|
||||
prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
|
||||
const bool flip = (coarse_edge->v2 == coarse_loop->v);
|
||||
|
@ -987,19 +955,14 @@ static void subdiv_foreach_edges_all_patches(SubdivForeachTaskContext *ctx,
|
|||
|
||||
static void subdiv_foreach_edges(SubdivForeachTaskContext *ctx, void *tls, int poly_index)
|
||||
{
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
subdiv_foreach_edges_all_patches(ctx, tls, coarse_poly);
|
||||
subdiv_foreach_edges_all_patches(ctx, tls, &ctx->coarse_polys[poly_index]);
|
||||
}
|
||||
|
||||
static void subdiv_foreach_boundary_edges(SubdivForeachTaskContext *ctx,
|
||||
void *tls,
|
||||
int coarse_edge_index)
|
||||
{
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MEdge *coarse_medge = BKE_mesh_edges(coarse_mesh);
|
||||
const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_edge_index];
|
||||
const int resolution = ctx->settings->resolution;
|
||||
const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
|
||||
const int num_subdiv_edges_per_coarse_edge = resolution - 1;
|
||||
|
@ -1128,11 +1091,7 @@ static void subdiv_foreach_loops_regular(SubdivForeachTaskContext *ctx,
|
|||
{
|
||||
const int resolution = ctx->settings->resolution;
|
||||
/* Base/coarse mesh information. */
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MEdge *coarse_medge = BKE_mesh_edges(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const int coarse_poly_index = coarse_poly - coarse_mpoly;
|
||||
const int coarse_poly_index = coarse_poly - ctx->coarse_polys;
|
||||
const int ptex_resolution = ptex_face_resolution_get(coarse_poly, resolution);
|
||||
const int ptex_inner_resolution = ptex_resolution - 2;
|
||||
const int num_subdiv_edges_per_coarse_edge = resolution - 1;
|
||||
|
@ -1188,11 +1147,12 @@ static void subdiv_foreach_loops_regular(SubdivForeachTaskContext *ctx,
|
|||
}
|
||||
}
|
||||
/* Loops for faces connecting inner ptex part with boundary. */
|
||||
const MLoop *prev_coarse_loop = &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
|
||||
const MLoop *prev_coarse_loop =
|
||||
&ctx->coarse_loops[coarse_poly->loopstart + coarse_poly->totloop - 1];
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
||||
const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
|
||||
const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
|
||||
const MLoop *coarse_loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_loop->e];
|
||||
const MEdge *prev_coarse_edge = &ctx->coarse_edges[prev_coarse_loop->e];
|
||||
const int start_edge_vertex = ctx->vertices_edge_offset +
|
||||
coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
|
||||
const bool flip = (coarse_edge->v2 == coarse_loop->v);
|
||||
|
@ -1322,11 +1282,7 @@ static void subdiv_foreach_loops_special(SubdivForeachTaskContext *ctx,
|
|||
{
|
||||
const int resolution = ctx->settings->resolution;
|
||||
/* Base/coarse mesh information. */
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MEdge *coarse_medge = BKE_mesh_edges(coarse_mesh);
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
const int coarse_poly_index = coarse_poly - coarse_mpoly;
|
||||
const int coarse_poly_index = coarse_poly - ctx->coarse_polys;
|
||||
const int ptex_face_resolution = ptex_face_resolution_get(coarse_poly, resolution);
|
||||
const int ptex_face_inner_resolution = ptex_face_resolution - 2;
|
||||
const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_face_resolution - 1);
|
||||
|
@ -1493,12 +1449,13 @@ static void subdiv_foreach_loops_special(SubdivForeachTaskContext *ctx,
|
|||
}
|
||||
}
|
||||
/* Loops for faces connecting inner ptex part with boundary. */
|
||||
const MLoop *prev_coarse_loop = &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
|
||||
const MLoop *prev_coarse_loop =
|
||||
&ctx->coarse_loops[coarse_poly->loopstart + coarse_poly->totloop - 1];
|
||||
for (int prev_corner = coarse_poly->totloop - 1, corner = 0; corner < coarse_poly->totloop;
|
||||
prev_corner = corner, corner++) {
|
||||
const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
|
||||
const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
|
||||
const MLoop *coarse_loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_loop->e];
|
||||
const MEdge *prev_coarse_edge = &ctx->coarse_edges[prev_coarse_loop->e];
|
||||
const bool flip = (coarse_edge->v2 == coarse_loop->v);
|
||||
const int start_edge_vertex = ctx->vertices_edge_offset +
|
||||
coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
|
||||
|
@ -1657,9 +1614,7 @@ static void subdiv_foreach_loops_special(SubdivForeachTaskContext *ctx,
|
|||
|
||||
static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx, void *tls, int poly_index)
|
||||
{
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
const MPoly *coarse_poly = &ctx->coarse_polys[poly_index];
|
||||
if (coarse_poly->totloop == 4) {
|
||||
subdiv_foreach_loops_regular(ctx, tls, coarse_poly);
|
||||
}
|
||||
|
@ -1679,9 +1634,7 @@ static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int p
|
|||
const int resolution = ctx->settings->resolution;
|
||||
const int start_poly_index = ctx->subdiv_polygon_offset[poly_index];
|
||||
/* Base/coarse mesh information. */
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
const MPoly *coarse_poly = &ctx->coarse_polys[poly_index];
|
||||
const int num_ptex_faces_per_poly = num_ptex_faces_per_poly_get(coarse_poly);
|
||||
const int ptex_resolution = ptex_face_resolution_get(coarse_poly, resolution);
|
||||
const int num_polys_per_ptex = num_polys_per_ptex_get(ptex_resolution);
|
||||
|
@ -1734,9 +1687,7 @@ static void subdiv_foreach_vertices_of_loose_edges_task(void *__restrict userdat
|
|||
const int resolution_1 = resolution - 1;
|
||||
const float inv_resolution_1 = 1.0f / (float)resolution_1;
|
||||
const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MEdge *coarse_edges = BKE_mesh_edges(coarse_mesh);
|
||||
const MEdge *coarse_edge = &coarse_edges[coarse_edge_index];
|
||||
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_edge_index];
|
||||
/* Subdivision vertices which corresponds to edge's v1 and v2. */
|
||||
const int subdiv_v1_index = ctx->vertices_corner_offset + coarse_edge->v1;
|
||||
const int subdiv_v2_index = ctx->vertices_corner_offset + coarse_edge->v2;
|
||||
|
@ -1773,9 +1724,8 @@ static void subdiv_foreach_single_geometry_vertices(SubdivForeachTaskContext *ct
|
|||
return;
|
||||
}
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
const MPoly *coarse_poly = &ctx->coarse_polys[poly_index];
|
||||
subdiv_foreach_corner_vertices(ctx, tls, coarse_poly);
|
||||
subdiv_foreach_edge_vertices(ctx, tls, coarse_poly);
|
||||
}
|
||||
|
@ -1784,12 +1734,10 @@ static void subdiv_foreach_single_geometry_vertices(SubdivForeachTaskContext *ct
|
|||
static void subdiv_foreach_mark_non_loose_geometry(SubdivForeachTaskContext *ctx)
|
||||
{
|
||||
const Mesh *coarse_mesh = ctx->coarse_mesh;
|
||||
const MPoly *coarse_mpoly = BKE_mesh_polys(coarse_mesh);
|
||||
const MLoop *coarse_mloop = BKE_mesh_loops(coarse_mesh);
|
||||
for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
|
||||
const MPoly *coarse_poly = &coarse_mpoly[poly_index];
|
||||
const MPoly *coarse_poly = &ctx->coarse_polys[poly_index];
|
||||
for (int corner = 0; corner < coarse_poly->totloop; corner++) {
|
||||
const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner];
|
||||
const MLoop *loop = &ctx->coarse_loops[coarse_poly->loopstart + corner];
|
||||
BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e);
|
||||
BLI_BITMAP_ENABLE(ctx->coarse_vertices_used_map, loop->v);
|
||||
}
|
||||
|
@ -1860,6 +1808,9 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
|
|||
{
|
||||
SubdivForeachTaskContext ctx = {0};
|
||||
ctx.coarse_mesh = coarse_mesh;
|
||||
ctx.coarse_edges = BKE_mesh_edges(coarse_mesh);
|
||||
ctx.coarse_polys = BKE_mesh_polys(coarse_mesh);
|
||||
ctx.coarse_loops = BKE_mesh_loops(coarse_mesh);
|
||||
ctx.settings = mesh_settings;
|
||||
ctx.foreach_context = context;
|
||||
subdiv_foreach_ctx_init(subdiv, &ctx);
|
||||
|
|
|
@ -520,8 +520,10 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
|
|||
* so don't try to preserve it and use memory. Crease values should also not be interpolated. */
|
||||
CustomData_MeshMasks mask = CD_MASK_EVERYTHING;
|
||||
mask.lmask &= ~CD_MASK_MULTIRES_GRIDS;
|
||||
/* Propagate edge creases so they can be used in another subdivision modifier (maintaining
|
||||
* existing behavior), but don't propagate vertex creases to avoid extra work when the result
|
||||
* isn't useful anyway. */
|
||||
mask.vmask &= ~CD_MASK_CREASE;
|
||||
mask.emask &= ~CD_MASK_CREASE;
|
||||
|
||||
SubdivMeshContext *subdiv_context = static_cast<SubdivMeshContext *>(foreach_context->user_data);
|
||||
subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex(
|
||||
|
@ -791,7 +793,6 @@ static void subdiv_copy_edge_data(SubdivMeshContext *ctx,
|
|||
{
|
||||
const int subdiv_edge_index = subdiv_edge - ctx->subdiv_edges;
|
||||
if (coarse_edge == nullptr) {
|
||||
/* TODO: Ensure crease layer isn't copied to result. */
|
||||
subdiv_edge->flag = 0;
|
||||
if (!ctx->settings->use_optimal_display) {
|
||||
subdiv_edge->flag |= ME_EDGEDRAW;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "BLI_map.hh"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_timeit.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
|
@ -374,12 +375,13 @@ struct PBVHBatches {
|
|||
no = CCG_elem_no(&args->ccg_key, elems[0]);
|
||||
}
|
||||
else {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
no += CCG_elem_no(&args->ccg_key, elems[j]);
|
||||
}
|
||||
normal_quad_v3(no,
|
||||
CCG_elem_co(&args->ccg_key, elems[3]),
|
||||
CCG_elem_co(&args->ccg_key, elems[2]),
|
||||
CCG_elem_co(&args->ccg_key, elems[1]),
|
||||
CCG_elem_co(&args->ccg_key, elems[0]));
|
||||
}
|
||||
|
||||
normalize_v3(no);
|
||||
short sno[3];
|
||||
|
||||
normal_float_to_short_v3(sno, no);
|
||||
|
@ -959,6 +961,8 @@ struct PBVHBatches {
|
|||
material_index = mat_index[poly_index];
|
||||
}
|
||||
|
||||
const blender::Span<MEdge> edges = args->me->edges();
|
||||
|
||||
/* Calculate number of edges*/
|
||||
int edge_count = 0;
|
||||
for (int i = 0; i < args->totprim; i++) {
|
||||
|
@ -969,7 +973,7 @@ struct PBVHBatches {
|
|||
}
|
||||
|
||||
int r_edges[3];
|
||||
BKE_mesh_looptri_get_real_edges(args->me, lt, r_edges);
|
||||
BKE_mesh_looptri_get_real_edges(edges.data(), args->mloop, lt, r_edges);
|
||||
|
||||
if (r_edges[0] != -1) {
|
||||
edge_count++;
|
||||
|
@ -994,7 +998,7 @@ struct PBVHBatches {
|
|||
}
|
||||
|
||||
int r_edges[3];
|
||||
BKE_mesh_looptri_get_real_edges(args->me, lt, r_edges);
|
||||
BKE_mesh_looptri_get_real_edges(edges.data(), args->mloop, lt, r_edges);
|
||||
|
||||
if (r_edges[0] != -1) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, vertex_i, vertex_i + 1);
|
||||
|
|
|
@ -412,15 +412,19 @@ static void gpencil_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgp
|
|||
}
|
||||
|
||||
/* Helper: Get previous keyframe (exclude breakdown type). */
|
||||
static bGPDframe *gpencil_get_previous_keyframe(bGPDlayer *gpl, int cfra)
|
||||
static bGPDframe *gpencil_get_previous_keyframe(bGPDlayer *gpl,
|
||||
int cfra,
|
||||
const bool exclude_breakdowns)
|
||||
{
|
||||
if (gpl->actframe != NULL && gpl->actframe->framenum < cfra &&
|
||||
gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN) {
|
||||
return gpl->actframe;
|
||||
if (gpl->actframe != NULL && gpl->actframe->framenum < cfra) {
|
||||
if ((!exclude_breakdowns) ||
|
||||
((exclude_breakdowns) && (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN))) {
|
||||
return gpl->actframe;
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH_BACKWARD (bGPDframe *, gpf, &gpl->frames) {
|
||||
if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
|
||||
if ((exclude_breakdowns) && (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN)) {
|
||||
continue;
|
||||
}
|
||||
if (gpf->framenum >= cfra) {
|
||||
|
@ -433,10 +437,12 @@ static bGPDframe *gpencil_get_previous_keyframe(bGPDlayer *gpl, int cfra)
|
|||
}
|
||||
|
||||
/* Helper: Get next keyframe (exclude breakdown type). */
|
||||
static bGPDframe *gpencil_get_next_keyframe(bGPDlayer *gpl, int cfra)
|
||||
static bGPDframe *gpencil_get_next_keyframe(bGPDlayer *gpl,
|
||||
int cfra,
|
||||
const bool exclude_breakdowns)
|
||||
{
|
||||
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
|
||||
if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
|
||||
if ((exclude_breakdowns) && (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN)) {
|
||||
continue;
|
||||
}
|
||||
if (gpf->framenum <= cfra) {
|
||||
|
@ -455,6 +461,7 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
|
|||
bGPdata *gpd = tgpi->gpd;
|
||||
bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
|
||||
bGPDframe *actframe = active_gpl->actframe;
|
||||
const bool exclude_breakdowns = (tgpi->flag & GP_TOOLFLAG_INTERPOLATE_EXCLUDE_BREAKDOWNS) != 0;
|
||||
|
||||
/* save initial factor for active layer to define shift limits */
|
||||
tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) /
|
||||
|
@ -483,10 +490,10 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
|
|||
tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
|
||||
|
||||
tgpil->gpl = gpl;
|
||||
bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, scene->r.cfra);
|
||||
bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, scene->r.cfra, exclude_breakdowns);
|
||||
tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpf, true);
|
||||
|
||||
gpf = gpencil_get_next_keyframe(gpl, scene->r.cfra);
|
||||
gpf = gpencil_get_next_keyframe(gpl, scene->r.cfra, exclude_breakdowns);
|
||||
tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpf, true);
|
||||
|
||||
BLI_addtail(&tgpi->ilayers, tgpil);
|
||||
|
@ -692,6 +699,9 @@ static bool gpencil_interpolate_set_init_values(bContext *C, wmOperator *op, tGP
|
|||
tgpi->flag,
|
||||
(GPENCIL_EDIT_MODE(tgpi->gpd) && RNA_boolean_get(op->ptr, "interpolate_selected_only")),
|
||||
GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED);
|
||||
SET_FLAG_FROM_TEST(tgpi->flag,
|
||||
RNA_boolean_get(op->ptr, "exclude_breakdowns"),
|
||||
GP_TOOLFLAG_INTERPOLATE_EXCLUDE_BREAKDOWNS);
|
||||
|
||||
tgpi->flipmode = RNA_enum_get(op->ptr, "flip");
|
||||
|
||||
|
@ -751,8 +761,9 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
|
|||
|
||||
/* Cannot interpolate if not between 2 frames. */
|
||||
int cfra = scene->r.cfra;
|
||||
bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, cfra);
|
||||
bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, cfra);
|
||||
const bool exclude_breakdowns = RNA_boolean_get(op->ptr, "exclude_breakdowns");
|
||||
bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, cfra, exclude_breakdowns);
|
||||
bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, cfra, exclude_breakdowns);
|
||||
if (ELEM(NULL, gpf_prv, gpf_next)) {
|
||||
BKE_report(
|
||||
op->reports,
|
||||
|
@ -972,6 +983,12 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot)
|
|||
"Only Selected",
|
||||
"Interpolate only selected strokes");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"exclude_breakdowns",
|
||||
false,
|
||||
"Exclude Breakdowns",
|
||||
"Exclude existing Breakdowns keyframes as interpolation extremes");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"flip",
|
||||
flip_modes,
|
||||
|
@ -1229,6 +1246,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
|
|||
const bool all_layers = (bool)(RNA_enum_get(op->ptr, "layers") == 1);
|
||||
const bool only_selected = (GPENCIL_EDIT_MODE(gpd) &&
|
||||
(RNA_boolean_get(op->ptr, "interpolate_selected_only") != 0));
|
||||
const bool exclude_breakdowns = RNA_boolean_get(op->ptr, "exclude_breakdowns");
|
||||
|
||||
eGP_InterpolateFlipMode flipmode = RNA_enum_get(op->ptr, "flip");
|
||||
|
||||
|
@ -1243,8 +1261,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
|
|||
BKE_curvemapping_init(ipo_settings->custom_ipo);
|
||||
|
||||
/* Cannot interpolate if not between 2 frames. */
|
||||
bGPDframe *gpf_prv = gpencil_get_previous_keyframe(active_gpl, cfra);
|
||||
bGPDframe *gpf_next = gpencil_get_next_keyframe(active_gpl, cfra);
|
||||
bGPDframe *gpf_prv = gpencil_get_previous_keyframe(active_gpl, cfra, exclude_breakdowns);
|
||||
bGPDframe *gpf_next = gpencil_get_next_keyframe(active_gpl, cfra, exclude_breakdowns);
|
||||
if (ELEM(NULL, gpf_prv, gpf_next)) {
|
||||
BKE_report(
|
||||
op->reports,
|
||||
|
@ -1268,8 +1286,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
|
|||
if (!BKE_gpencil_layer_is_editable(gpl)) {
|
||||
continue;
|
||||
}
|
||||
gpf_prv = gpencil_get_previous_keyframe(gpl, cfra);
|
||||
gpf_next = gpencil_get_next_keyframe(gpl, cfra);
|
||||
gpf_prv = gpencil_get_previous_keyframe(gpl, cfra, exclude_breakdowns);
|
||||
gpf_next = gpencil_get_next_keyframe(gpl, cfra, exclude_breakdowns);
|
||||
|
||||
/* Need a set of frames to interpolate. */
|
||||
if ((gpf_prv == NULL) || (gpf_next == NULL)) {
|
||||
|
@ -1433,6 +1451,9 @@ static void gpencil_interpolate_seq_ui(bContext *C, wmOperator *op)
|
|||
uiItemR(row, op->ptr, "interpolate_selected_only", 0, NULL, ICON_NONE);
|
||||
}
|
||||
|
||||
row = uiLayoutRow(layout, true);
|
||||
uiItemR(row, op->ptr, "exclude_breakdowns", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, true);
|
||||
uiItemR(row, op->ptr, "flip", 0, NULL, ICON_NONE);
|
||||
|
||||
|
@ -1602,6 +1623,12 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
|
|||
"Only Selected",
|
||||
"Interpolate only selected strokes");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"exclude_breakdowns",
|
||||
false,
|
||||
"Exclude Breakdowns",
|
||||
"Exclude existing Breakdowns keyframes as interpolation extremes");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"flip",
|
||||
flip_modes,
|
||||
|
|
|
@ -1629,8 +1629,8 @@ static bool ui_drag_toggle_set_xy_xy(
|
|||
bool changed = false;
|
||||
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
||||
float xy_a_block[2] = {float(xy_src[0]), float(xy_src[0])};
|
||||
float xy_b_block[2] = {float(xy_dst[0]), float(xy_dst[0])};
|
||||
float xy_a_block[2] = {float(xy_src[0]), float(xy_src[1])};
|
||||
float xy_b_block[2] = {float(xy_dst[0]), float(xy_dst[1])};
|
||||
|
||||
ui_window_to_block_fl(region, block, &xy_a_block[0], &xy_a_block[1]);
|
||||
ui_window_to_block_fl(region, block, &xy_b_block[0], &xy_b_block[1]);
|
||||
|
|
|
@ -3199,6 +3199,7 @@ void uiItemPopoverPanel_ptr(
|
|||
Panel panel{};
|
||||
panel.type = pt;
|
||||
panel.layout = layout;
|
||||
panel.flag = PNL_POPOVER;
|
||||
pt->draw_header(C, &panel);
|
||||
}
|
||||
uiBut *but = ui_item_menu(
|
||||
|
|
|
@ -516,7 +516,7 @@ static ARegion *template_ID_search_menu_item_tooltip(
|
|||
ID *active_id = static_cast<ID *>(active);
|
||||
StructRNA *type = RNA_property_pointer_type(&template_ui->ptr, template_ui->prop);
|
||||
|
||||
uiSearchItemTooltipData tooltip_data = {0};
|
||||
uiSearchItemTooltipData tooltip_data = {{0}};
|
||||
|
||||
tooltip_data.name = active_id->name + 2;
|
||||
BLI_snprintf(tooltip_data.description,
|
||||
|
|
|
@ -1897,17 +1897,9 @@ static void knife_start_cut(KnifeTool_OpData *kcd)
|
|||
kcd->mdata.is_stored = false;
|
||||
|
||||
if (kcd->prev.vert == NULL && kcd->prev.edge == NULL) {
|
||||
float origin[3], origin_ofs[3];
|
||||
float ofs_local[3];
|
||||
|
||||
negate_v3_v3(ofs_local, kcd->vc.rv3d->ofs);
|
||||
|
||||
knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
|
||||
|
||||
if (!isect_line_plane_v3(
|
||||
kcd->prev.cage, origin, origin_ofs, ofs_local, kcd->vc.rv3d->viewinv[2])) {
|
||||
zero_v3(kcd->prev.cage);
|
||||
}
|
||||
ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, ofs_local, kcd->curr.mval, kcd->prev.cage);
|
||||
|
||||
copy_v3_v3(kcd->prev.co, kcd->prev.cage); /* TODO: do we need this? */
|
||||
copy_v3_v3(kcd->curr.cage, kcd->prev.cage);
|
||||
|
|
|
@ -1832,14 +1832,27 @@ SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
|
|||
SculptBrushTest *test,
|
||||
char falloff_shape)
|
||||
{
|
||||
if (!ss->cache && !ss->filter_cache) {
|
||||
falloff_shape = PAINT_FALLOFF_SHAPE_SPHERE;
|
||||
}
|
||||
|
||||
SCULPT_brush_test_init(ss, test);
|
||||
SculptBrushTestFn sculpt_brush_test_sq_fn;
|
||||
if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
|
||||
sculpt_brush_test_sq_fn = SCULPT_brush_test_sphere_sq;
|
||||
}
|
||||
else {
|
||||
float view_normal[3];
|
||||
|
||||
if (ss->cache) {
|
||||
copy_v3_v3(view_normal, ss->cache->view_normal);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(view_normal, ss->filter_cache->view_normal);
|
||||
}
|
||||
|
||||
/* PAINT_FALLOFF_SHAPE_TUBE */
|
||||
plane_from_point_normal_v3(test->plane_view, test->location, ss->cache->view_normal);
|
||||
plane_from_point_normal_v3(test->plane_view, test->location, view_normal);
|
||||
sculpt_brush_test_sq_fn = SCULPT_brush_test_circle_sq;
|
||||
}
|
||||
return sculpt_brush_test_sq_fn;
|
||||
|
|
|
@ -185,9 +185,8 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush
|
|||
return true;
|
||||
}
|
||||
|
||||
if (automasking_flags &
|
||||
(BRUSH_AUTOMASKING_BOUNDARY_EDGES | BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS |
|
||||
BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL)) {
|
||||
if (automasking_flags & (BRUSH_AUTOMASKING_BOUNDARY_EDGES |
|
||||
BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS | BRUSH_AUTOMASKING_VIEW_NORMAL)) {
|
||||
return brush && brush->automasking_boundary_edges_propagation_steps != 1;
|
||||
}
|
||||
return false;
|
||||
|
@ -507,6 +506,16 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
|
|||
return 1.0f;
|
||||
}
|
||||
|
||||
float mask = 1.0f;
|
||||
|
||||
/* Since brush normal mode depends on the current mirror symmery pass
|
||||
* it is not folded into the factor cache (when it exists).
|
||||
*/
|
||||
if ((ss->cache || ss->filter_cache) &&
|
||||
(automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) {
|
||||
mask *= automasking_brush_normal_factor(automasking, ss, vert, automask_data);
|
||||
}
|
||||
|
||||
/* If the cache is initialized with valid info, use the cache. This is used when the
|
||||
* automasking information can't be computed in real time per vertex and needs to be
|
||||
* initialized for the whole mesh when the stroke starts. */
|
||||
|
@ -517,7 +526,7 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
|
|||
factor *= sculpt_automasking_cavity_factor(automasking, ss, vert);
|
||||
}
|
||||
|
||||
return factor;
|
||||
return factor * mask;
|
||||
}
|
||||
|
||||
uchar stroke_id = ss->attrs.automasking_stroke_id ?
|
||||
|
@ -554,13 +563,6 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
|
|||
}
|
||||
}
|
||||
|
||||
float mask = 1.0f;
|
||||
|
||||
if ((ss->cache || ss->filter_cache) &&
|
||||
(automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) {
|
||||
mask *= automasking_brush_normal_factor(automasking, ss, vert, automask_data);
|
||||
}
|
||||
|
||||
if ((ss->cache || ss->filter_cache) &&
|
||||
(automasking->settings.flags & BRUSH_AUTOMASKING_VIEW_NORMAL)) {
|
||||
mask *= automasking_view_normal_factor(automasking, ss, vert, automask_data);
|
||||
|
@ -782,9 +784,6 @@ static void sculpt_normal_occlusion_automasking_fill(AutomaskingCache *automaski
|
|||
|
||||
float f = *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor);
|
||||
|
||||
if (int(mode) & BRUSH_AUTOMASKING_BRUSH_NORMAL) {
|
||||
f *= automasking_brush_normal_factor(automasking, ss, vertex, &nodedata);
|
||||
}
|
||||
if (int(mode) & BRUSH_AUTOMASKING_VIEW_NORMAL) {
|
||||
if (int(mode) & BRUSH_AUTOMASKING_VIEW_OCCLUSION) {
|
||||
f *= automasking_view_occlusion_factor(automasking, ss, vertex, -1, &nodedata);
|
||||
|
@ -940,8 +939,7 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
|
|||
|
||||
/* Subtractive modes. */
|
||||
int normal_bits = sculpt_automasking_mode_effective_bits(sd, brush) &
|
||||
(BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL |
|
||||
BRUSH_AUTOMASKING_VIEW_OCCLUSION);
|
||||
(BRUSH_AUTOMASKING_VIEW_NORMAL | BRUSH_AUTOMASKING_VIEW_OCCLUSION);
|
||||
|
||||
if (normal_bits) {
|
||||
sculpt_normal_occlusion_automasking_fill(automasking, ob, (eAutomasking_flag)normal_bits);
|
||||
|
|
|
@ -362,12 +362,18 @@ static void do_paint_pixels(void *__restrict userdata,
|
|||
}
|
||||
bool pixels_painted = false;
|
||||
if (image_buffer->rect_float != nullptr) {
|
||||
pixels_painted = kernel_float4.paint(
|
||||
pbvh_data.geom_primitives, node_data.uv_primitives, pixel_row, image_buffer, &automask_data);
|
||||
pixels_painted = kernel_float4.paint(pbvh_data.geom_primitives,
|
||||
node_data.uv_primitives,
|
||||
pixel_row,
|
||||
image_buffer,
|
||||
&automask_data);
|
||||
}
|
||||
else {
|
||||
pixels_painted = kernel_byte4.paint(
|
||||
pbvh_data.geom_primitives, node_data.uv_primitives, pixel_row, image_buffer, &automask_data);
|
||||
pixels_painted = kernel_byte4.paint(pbvh_data.geom_primitives,
|
||||
node_data.uv_primitives,
|
||||
pixel_row,
|
||||
image_buffer,
|
||||
&automask_data);
|
||||
}
|
||||
|
||||
if (pixels_painted) {
|
||||
|
|
|
@ -216,13 +216,25 @@ static bool outliner_operation_tree_element_poll(bContext *C)
|
|||
}
|
||||
|
||||
static void unlink_action_fn(bContext *C,
|
||||
ReportList * /*reports*/,
|
||||
ReportList *reports,
|
||||
Scene * /*scene*/,
|
||||
TreeElement * /*te*/,
|
||||
TreeStoreElem *tsep,
|
||||
TreeStoreElem * /*tselem*/,
|
||||
TreeStoreElem *tselem,
|
||||
void * /*user_data*/)
|
||||
{
|
||||
if (!tsep || !TSE_IS_REAL_ID(tsep)) {
|
||||
/* Valid case, no parent element of the action or it is not an ID (could be a #TSE_ID_BASE
|
||||
* for example) so there's no data to unlink from. */
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"Cannot unlink action '%s'. It's not clear which object or object-data it "
|
||||
"should be unlinked from, there's no object or object-data as parent in the "
|
||||
"Outliner tree",
|
||||
tselem->id->name + 2);
|
||||
return;
|
||||
}
|
||||
|
||||
/* just set action to nullptr */
|
||||
BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, nullptr);
|
||||
DEG_id_tag_update(tsep->id, ID_RECALC_ANIMATION);
|
||||
|
|
|
@ -175,53 +175,28 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
|
|||
return status;
|
||||
}
|
||||
|
||||
static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
|
||||
static void apply_shear_value(TransInfo *t, const float value)
|
||||
{
|
||||
float smat[3][3], axismat[3][3], axismat_inv[3][3], mat_final[3][3];
|
||||
float value;
|
||||
int i;
|
||||
char str[UI_MAX_DRAW_STR];
|
||||
const bool is_local_center = transdata_check_local_center(t, t->around);
|
||||
|
||||
value = t->values[0] + t->values_modal_offset[0];
|
||||
|
||||
transform_snap_increment(t, &value);
|
||||
|
||||
applyNumInput(&t->num, &value);
|
||||
|
||||
t->values_final[0] = value;
|
||||
|
||||
/* header print for NumInput */
|
||||
if (hasNumInput(&t->num)) {
|
||||
char c[NUM_STR_REP_LEN];
|
||||
|
||||
outputNumInput(&(t->num), c, &t->scene->unit);
|
||||
|
||||
BLI_snprintf(str, sizeof(str), TIP_("Shear: %s %s"), c, t->proptext);
|
||||
}
|
||||
else {
|
||||
/* default header print */
|
||||
BLI_snprintf(str,
|
||||
sizeof(str),
|
||||
TIP_("Shear: %.3f %s (Press X or Y to set shear axis)"),
|
||||
value,
|
||||
t->proptext);
|
||||
}
|
||||
|
||||
float smat[3][3];
|
||||
unit_m3(smat);
|
||||
smat[1][0] = value;
|
||||
|
||||
float axismat_inv[3][3];
|
||||
copy_v3_v3(axismat_inv[0], t->spacemtx[t->orient_axis_ortho]);
|
||||
copy_v3_v3(axismat_inv[2], t->spacemtx[t->orient_axis]);
|
||||
cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]);
|
||||
float axismat[3][3];
|
||||
invert_m3_m3(axismat, axismat_inv);
|
||||
|
||||
float mat_final[3][3];
|
||||
mul_m3_series(mat_final, axismat_inv, smat, axismat);
|
||||
|
||||
const bool is_local_center = transdata_check_local_center(t, t->around);
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
for (int i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
@ -241,16 +216,117 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
|
|||
BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_shear_fn, &settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool uv_shear_in_clip_bounds_test(const TransInfo *t, const float value)
|
||||
{
|
||||
const int axis = t->orient_axis_ortho;
|
||||
if (axis < 0 || 1 < axis) {
|
||||
return true; /* Non standard axis, nothing to do. */
|
||||
}
|
||||
const float *center = t->center_global;
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
for (int i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
if (td->factor < 1.0f) {
|
||||
continue; /* Proportional edit, will get picked up in next phase. */
|
||||
}
|
||||
|
||||
float uv[2];
|
||||
sub_v2_v2v2(uv, td->iloc, center);
|
||||
uv[axis] = uv[axis] + value * uv[1 - axis] * (2 * axis - 1);
|
||||
add_v2_v2(uv, center);
|
||||
/* TODO: udim support. */
|
||||
if (uv[axis] < 0.0f || 1.0f < uv[axis]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool clip_uv_transform_shear(const TransInfo *t, float *vec, float *vec_inside_bounds)
|
||||
{
|
||||
float value = vec[0];
|
||||
if (uv_shear_in_clip_bounds_test(t, value)) {
|
||||
vec_inside_bounds[0] = value; /* Store for next iteration. */
|
||||
return false; /* Nothing to do. */
|
||||
}
|
||||
float value_inside_bounds = vec_inside_bounds[0];
|
||||
if (!uv_shear_in_clip_bounds_test(t, value_inside_bounds)) {
|
||||
return false; /* No known way to fix, may as well shear anyway. */
|
||||
}
|
||||
const int max_i = 32; /* Limit iteration, mainly for debugging. */
|
||||
for (int i = 0; i < max_i; i++) {
|
||||
/* Binary search. */
|
||||
const float value_mid = (value_inside_bounds + value) / 2.0f;
|
||||
if (value_mid == value_inside_bounds || value_mid == value) {
|
||||
break; /* float precision reached. */
|
||||
}
|
||||
if (uv_shear_in_clip_bounds_test(t, value_mid)) {
|
||||
value_inside_bounds = value_mid;
|
||||
}
|
||||
else {
|
||||
value = value_mid;
|
||||
}
|
||||
}
|
||||
|
||||
vec_inside_bounds[0] = value_inside_bounds; /* Store for next iteration. */
|
||||
vec[0] = value_inside_bounds; /* Update shear value. */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void apply_shear(TransInfo *t, const int UNUSED(mval[2]))
|
||||
{
|
||||
float value = t->values[0] + t->values_modal_offset[0];
|
||||
transform_snap_increment(t, &value);
|
||||
applyNumInput(&t->num, &value);
|
||||
t->values_final[0] = value;
|
||||
|
||||
apply_shear_value(t, value);
|
||||
|
||||
if (t->flag & T_CLIP_UV) {
|
||||
if (clip_uv_transform_shear(t, t->values_final, t->values_inside_constraints)) {
|
||||
apply_shear_value(t, t->values_final[0]);
|
||||
}
|
||||
|
||||
/* In proportional edit it can happen that */
|
||||
/* vertices in the radius of the brush end */
|
||||
/* outside the clipping area */
|
||||
/* XXX HACK - dg */
|
||||
if (t->flag & T_PROP_EDIT) {
|
||||
clipUVData(t);
|
||||
}
|
||||
}
|
||||
|
||||
recalcData(t);
|
||||
|
||||
char str[UI_MAX_DRAW_STR];
|
||||
/* header print for NumInput */
|
||||
if (hasNumInput(&t->num)) {
|
||||
char c[NUM_STR_REP_LEN];
|
||||
outputNumInput(&(t->num), c, &t->scene->unit);
|
||||
BLI_snprintf(str, sizeof(str), TIP_("Shear: %s %s"), c, t->proptext);
|
||||
}
|
||||
else {
|
||||
/* default header print */
|
||||
BLI_snprintf(str,
|
||||
sizeof(str),
|
||||
TIP_("Shear: %.3f %s (Press X or Y to set shear axis)"),
|
||||
value,
|
||||
t->proptext);
|
||||
}
|
||||
|
||||
ED_area_status_text(t->area, str);
|
||||
}
|
||||
|
||||
void initShear(TransInfo *t)
|
||||
{
|
||||
t->mode = TFM_SHEAR;
|
||||
t->transform = applyShear;
|
||||
t->transform = apply_shear;
|
||||
t->handleEvent = handleEventShear;
|
||||
|
||||
if (t->orient_axis == t->orient_axis_ortho) {
|
||||
|
|
|
@ -627,10 +627,9 @@ static eSnapFlag snap_flag_from_spacetype(TransInfo *t)
|
|||
/* These editors have their own "Auto-Snap" activation option.
|
||||
* See #getAnimEdit_SnapMode. */
|
||||
return eSnapFlag(0);
|
||||
default:
|
||||
BLI_assert(false);
|
||||
break;
|
||||
}
|
||||
/* #SPACE_EMPTY.
|
||||
* It can happen when the operator is called via a handle in `bpy.app.handlers`. */
|
||||
return eSnapFlag(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1474,6 +1474,9 @@ struct EdgeFeatData {
|
|||
Object *ob_eval; /* For evaluated materials. */
|
||||
const MLoopTri *mlooptri;
|
||||
const int *material_indices;
|
||||
blender::Span<MEdge> edges;
|
||||
blender::Span<MLoop> loops;
|
||||
blender::Span<MPoly> polys;
|
||||
LineartTriangle *tri_array;
|
||||
LineartVert *v_array;
|
||||
float crease_threshold;
|
||||
|
@ -1639,13 +1642,11 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
|
|||
}
|
||||
|
||||
if (!only_contour) {
|
||||
const MPoly *polys = BKE_mesh_polys(me);
|
||||
|
||||
if (ld->conf.use_crease) {
|
||||
bool do_crease = true;
|
||||
if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth &&
|
||||
(polys[mlooptri[f1].poly].flag & ME_SMOOTH) &&
|
||||
(polys[mlooptri[f2].poly].flag & ME_SMOOTH)) {
|
||||
(e_feat_data->polys[mlooptri[f1].poly].flag & ME_SMOOTH) &&
|
||||
(e_feat_data->polys[mlooptri[f2].poly].flag & ME_SMOOTH)) {
|
||||
do_crease = false;
|
||||
}
|
||||
if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < e_feat_data->crease_threshold)) {
|
||||
|
@ -1677,13 +1678,12 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
|
|||
}
|
||||
}
|
||||
|
||||
const MEdge *edges = BKE_mesh_edges(me);
|
||||
|
||||
int real_edges[3];
|
||||
BKE_mesh_looptri_get_real_edges(me, &mlooptri[i / 3], real_edges);
|
||||
BKE_mesh_looptri_get_real_edges(
|
||||
e_feat_data->edges.data(), e_feat_data->loops.data(), &mlooptri[i / 3], real_edges);
|
||||
|
||||
if (real_edges[i % 3] >= 0) {
|
||||
const MEdge *medge = &edges[real_edges[i % 3]];
|
||||
const MEdge *medge = &e_feat_data->edges[real_edges[i % 3]];
|
||||
|
||||
if (ld->conf.use_crease && ld->conf.sharp_as_crease && (medge->flag & ME_SHARP)) {
|
||||
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
|
||||
|
@ -1785,6 +1785,8 @@ static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
|
|||
|
||||
struct TriData {
|
||||
LineartObjectInfo *ob_info;
|
||||
blender::Span<MVert> verts;
|
||||
blender::Span<MLoop> loops;
|
||||
const MLoopTri *mlooptri;
|
||||
const int *material_indices;
|
||||
LineartVert *vert_arr;
|
||||
|
@ -1798,13 +1800,13 @@ static void lineart_load_tri_task(void *__restrict userdata,
|
|||
const TaskParallelTLS *__restrict /*tls*/)
|
||||
{
|
||||
TriData *tri_task_data = (TriData *)userdata;
|
||||
Mesh *me = tri_task_data->ob_info->original_me;
|
||||
LineartObjectInfo *ob_info = tri_task_data->ob_info;
|
||||
const blender::Span<MVert> verts = tri_task_data->verts;
|
||||
const blender::Span<MLoop> loops = tri_task_data->loops;
|
||||
const MLoopTri *mlooptri = &tri_task_data->mlooptri[i];
|
||||
const int *material_indices = tri_task_data->material_indices;
|
||||
LineartVert *vert_arr = tri_task_data->vert_arr;
|
||||
LineartTriangle *tri = tri_task_data->tri_arr;
|
||||
const MLoop *loops = BKE_mesh_loops(me);
|
||||
|
||||
tri = (LineartTriangle *)(((uchar *)tri) + tri_task_data->lineart_triangle_size * i);
|
||||
|
||||
|
@ -1837,7 +1839,6 @@ static void lineart_load_tri_task(void *__restrict userdata,
|
|||
|
||||
double gn[3];
|
||||
float no[3];
|
||||
const MVert *verts = BKE_mesh_verts(me);
|
||||
normal_tri_v3(no, verts[v1].co, verts[v2].co, verts[v3].co);
|
||||
copy_v3db_v3fl(gn, no);
|
||||
mul_v3_mat3_m4v3_db(tri->gn, ob_info->normal, gn);
|
||||
|
@ -2043,6 +2044,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
|
|||
TriData tri_data;
|
||||
tri_data.ob_info = ob_info;
|
||||
tri_data.mlooptri = mlooptri;
|
||||
tri_data.verts = me->verts();
|
||||
tri_data.material_indices = material_indices;
|
||||
tri_data.vert_arr = la_v_arr;
|
||||
tri_data.tri_arr = la_tri_arr;
|
||||
|
@ -2072,6 +2074,9 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
|
|||
edge_feat_data.ob_eval = ob_info->original_ob_eval;
|
||||
edge_feat_data.mlooptri = mlooptri;
|
||||
edge_feat_data.material_indices = material_indices;
|
||||
edge_feat_data.edges = me->edges();
|
||||
edge_feat_data.polys = me->polys();
|
||||
edge_feat_data.loops = me->loops();
|
||||
edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
|
||||
edge_feat_data.tri_array = la_tri_arr;
|
||||
edge_feat_data.v_array = la_v_arr;
|
||||
|
|
|
@ -177,7 +177,8 @@ void BKE_mesh_calc_poly_normal(const struct MPoly * /*mpoly*/,
|
|||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
void BKE_mesh_looptri_get_real_edges(const struct Mesh * /*mesh*/,
|
||||
void BKE_mesh_looptri_get_real_edges(const struct MEdge * /*edges*/,
|
||||
const struct MLoop * /*loops*/,
|
||||
const struct MLoopTri * /*looptri*/,
|
||||
int UNUSED(r_edges[3]))
|
||||
{
|
||||
|
|
|
@ -173,7 +173,6 @@ static void get_cols(const CDStreamConfig &config,
|
|||
{
|
||||
const float cscale = 1.0f / 255.0f;
|
||||
const MPoly *polys = config.mpoly;
|
||||
const MLoop *mloops = config.mloop;
|
||||
const MCol *cfaces = static_cast<const MCol *>(cd_data);
|
||||
|
||||
buffer.reserve(config.totvert);
|
||||
|
@ -184,11 +183,9 @@ static void get_cols(const CDStreamConfig &config,
|
|||
for (int i = 0; i < config.totpoly; i++) {
|
||||
const MPoly *p = &polys[i];
|
||||
const MCol *cface = &cfaces[p->loopstart + p->totloop];
|
||||
const MLoop *mloop = &mloops[p->loopstart + p->totloop];
|
||||
|
||||
for (int j = 0; j < p->totloop; j++) {
|
||||
cface--;
|
||||
mloop--;
|
||||
|
||||
col[0] = cface->a * cscale;
|
||||
col[1] = cface->r * cscale;
|
||||
|
|
|
@ -899,10 +899,18 @@ typedef struct BooleanModifierData {
|
|||
float double_threshold;
|
||||
char operation;
|
||||
char solver;
|
||||
/** #BooleanModifierMaterialMode. */
|
||||
char material_mode;
|
||||
char flag;
|
||||
char bm_flag;
|
||||
char _pad[7];
|
||||
} BooleanModifierData;
|
||||
|
||||
typedef enum BooleanModifierMaterialMode {
|
||||
eBooleanModifierMaterialMode_Index = 0,
|
||||
eBooleanModifierMaterialMode_Transfer = 1,
|
||||
} BooleanModifierMaterialMode;
|
||||
|
||||
/** #BooleanModifierData.operation */
|
||||
typedef enum {
|
||||
eBooleanModifierOp_Intersect = 0,
|
||||
|
|
|
@ -1199,6 +1199,8 @@ typedef enum eGP_Interpolate_SettingsFlag {
|
|||
GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS = (1 << 0),
|
||||
/* apply interpolation to only selected */
|
||||
GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED = (1 << 1),
|
||||
/* Exclude breakdown keyframe type as extreme */
|
||||
GP_TOOLFLAG_INTERPOLATE_EXCLUDE_BREAKDOWNS = (1 << 2),
|
||||
} eGP_Interpolate_SettingsFlag;
|
||||
|
||||
/** #GP_Interpolate_Settings.type */
|
||||
|
|
|
@ -2760,6 +2760,24 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
|
|||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem material_mode_items[] = {
|
||||
{eBooleanModifierMaterialMode_Index,
|
||||
"INDEX",
|
||||
0,
|
||||
"Index Based",
|
||||
"Set the material on new faces based on the order of the material slot lists. If a "
|
||||
"material doesn't exist on the modifier object, the face will use the same material slot "
|
||||
"or the first if the object doesn't have enough slots"},
|
||||
{eBooleanModifierMaterialMode_Transfer,
|
||||
"TRANSFER",
|
||||
0,
|
||||
"Transfer",
|
||||
"Transfer materials from non-empty slots to the result mesh, adding new materials as "
|
||||
"necessary. For empty slots, fall back to using the same material index as the operand "
|
||||
"mesh"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "BooleanModifier", "Modifier");
|
||||
RNA_def_struct_ui_text(srna, "Boolean Modifier", "Boolean operations modifier");
|
||||
RNA_def_struct_sdna(srna, "BooleanModifierData");
|
||||
|
@ -2819,6 +2837,12 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Hole Tolerant", "Better results when there are holes (slower)");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "material_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, material_mode_items);
|
||||
RNA_def_property_enum_default(prop, eBooleanModifierMaterialMode_Index);
|
||||
RNA_def_property_ui_text(prop, "Material Mode", "Method for setting materials on the new faces");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
/* BMesh debugging options, only used when G_DEBUG is set */
|
||||
|
||||
/* BMesh intersection options */
|
||||
|
|
|
@ -323,6 +323,7 @@ const EnumPropertyItem rna_enum_object_axis_items[] = {
|
|||
# include "BKE_deform.h"
|
||||
# include "BKE_effect.h"
|
||||
# include "BKE_global.h"
|
||||
# include "BKE_gpencil_modifier.h"
|
||||
# include "BKE_key.h"
|
||||
# include "BKE_material.h"
|
||||
# include "BKE_mesh.h"
|
||||
|
@ -1949,6 +1950,8 @@ bool rna_Object_greasepencil_modifiers_override_apply(Main *bmain,
|
|||
GpencilModifierData *mod_dst = ED_object_gpencil_modifier_add(
|
||||
NULL, bmain, NULL, ob_dst, mod_src->name, mod_src->type);
|
||||
|
||||
BKE_gpencil_modifier_copydata(mod_src, mod_dst);
|
||||
|
||||
BLI_remlink(&ob_dst->greasepencil_modifiers, mod_dst);
|
||||
/* This handles NULL anchor as expected by adding at head of list. */
|
||||
BLI_insertlinkafter(&ob_dst->greasepencil_modifiers, mod_anchor, mod_dst);
|
||||
|
|
|
@ -377,21 +377,31 @@ static void BMD_mesh_intersection(BMesh *bm,
|
|||
|
||||
#ifdef WITH_GMP
|
||||
|
||||
/* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob.
|
||||
* If a material doesn't exist in the dst_ob, the mapping just goes to the same slot
|
||||
* or to zero if there aren't enough slots in the destination. */
|
||||
static Array<short> get_material_remap_index_based(Object *dest_ob, Object *src_ob)
|
||||
{
|
||||
int n = src_ob->totcol;
|
||||
if (n <= 0) {
|
||||
n = 1;
|
||||
}
|
||||
Array<short> remap(n);
|
||||
BKE_object_material_remap_calc(dest_ob, src_ob, remap.data());
|
||||
return remap;
|
||||
}
|
||||
|
||||
/* Get a mapping from material slot numbers in the source geometry to slot numbers in the result
|
||||
* geometry. The material is added to the result geometry if it doesn't already use it. */
|
||||
static Array<short> get_material_remap(Object &object,
|
||||
const Mesh &mesh,
|
||||
VectorSet<Material *> &materials)
|
||||
static Array<short> get_material_remap_transfer(Object &object,
|
||||
const Mesh &mesh,
|
||||
VectorSet<Material *> &materials)
|
||||
{
|
||||
const int material_num = mesh.totcol;
|
||||
if (material_num == 0) {
|
||||
/* Necessary for faces using the default material when there are no material slots. */
|
||||
return Array<short>({materials.index_of_or_add(nullptr)});
|
||||
}
|
||||
Array<short> map(material_num);
|
||||
for (const int i : IndexRange(material_num)) {
|
||||
Material *material = BKE_object_material_get_eval(&object, i + 1);
|
||||
map[i] = materials.index_of_or_add(material);
|
||||
map[i] = material ? materials.index_of_or_add(material) : -1;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
@ -403,7 +413,6 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||
Vector<const Mesh *> meshes;
|
||||
Vector<float4x4 *> obmats;
|
||||
|
||||
VectorSet<Material *> materials;
|
||||
Vector<Array<short>> material_remaps;
|
||||
|
||||
# ifdef DEBUG_TIME
|
||||
|
@ -417,12 +426,18 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||
meshes.append(mesh);
|
||||
obmats.append((float4x4 *)&ctx->object->object_to_world);
|
||||
material_remaps.append({});
|
||||
if (mesh->totcol == 0) {
|
||||
/* Necessary for faces using the default material when there are no material slots. */
|
||||
materials.add(nullptr);
|
||||
}
|
||||
else {
|
||||
materials.add_multiple({mesh->mat, mesh->totcol});
|
||||
|
||||
const BooleanModifierMaterialMode material_mode = BooleanModifierMaterialMode(
|
||||
bmd->material_mode);
|
||||
VectorSet<Material *> materials;
|
||||
if (material_mode == eBooleanModifierMaterialMode_Transfer) {
|
||||
if (mesh->totcol == 0) {
|
||||
/* Necessary for faces using the default material when there are no material slots. */
|
||||
materials.add(nullptr);
|
||||
}
|
||||
else {
|
||||
materials.add_multiple({mesh->mat, mesh->totcol});
|
||||
}
|
||||
}
|
||||
|
||||
if (bmd->flag & eBooleanModifierFlag_Object) {
|
||||
|
@ -433,7 +448,12 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||
BKE_mesh_wrapper_ensure_mdata(mesh_operand);
|
||||
meshes.append(mesh_operand);
|
||||
obmats.append((float4x4 *)&bmd->object->object_to_world);
|
||||
material_remaps.append(get_material_remap(*bmd->object, *mesh_operand, materials));
|
||||
if (material_mode == eBooleanModifierMaterialMode_Index) {
|
||||
material_remaps.append(get_material_remap_index_based(ctx->object, bmd->object));
|
||||
}
|
||||
else {
|
||||
material_remaps.append(get_material_remap_transfer(*bmd->object, *mesh_operand, materials));
|
||||
}
|
||||
}
|
||||
else if (bmd->flag & eBooleanModifierFlag_Collection) {
|
||||
Collection *collection = bmd->collection;
|
||||
|
@ -448,7 +468,12 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||
BKE_mesh_wrapper_ensure_mdata(collection_mesh);
|
||||
meshes.append(collection_mesh);
|
||||
obmats.append((float4x4 *)&ob->object_to_world);
|
||||
material_remaps.append(get_material_remap(*ob, *collection_mesh, materials));
|
||||
if (material_mode == eBooleanModifierMaterialMode_Index) {
|
||||
material_remaps.append(get_material_remap_index_based(ctx->object, ob));
|
||||
}
|
||||
else {
|
||||
material_remaps.append(get_material_remap_transfer(*ob, *collection_mesh, materials));
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
||||
|
@ -466,10 +491,14 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||
hole_tolerant,
|
||||
bmd->operation,
|
||||
nullptr);
|
||||
MEM_SAFE_FREE(result->mat);
|
||||
result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__);
|
||||
result->totcol = materials.size();
|
||||
MutableSpan(result->mat, result->totcol).copy_from(materials);
|
||||
|
||||
if (material_mode == eBooleanModifierMaterialMode_Transfer) {
|
||||
MEM_SAFE_FREE(result->mat);
|
||||
result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__);
|
||||
result->totcol = materials.size();
|
||||
MutableSpan(result->mat, result->totcol).copy_from(materials);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
@ -610,6 +639,7 @@ static void solver_options_panel_draw(const bContext * /*C*/, Panel *panel)
|
|||
|
||||
uiLayout *col = uiLayoutColumn(layout, true);
|
||||
if (use_exact) {
|
||||
uiItemR(col, ptr, "material_mode", 0, IFACE_("Materials"), ICON_NONE);
|
||||
/* When operand is collection, we always use_self. */
|
||||
if (RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object) {
|
||||
uiItemR(col, ptr, "use_self", 0, nullptr, ICON_NONE);
|
||||
|
|
|
@ -120,7 +120,7 @@ static void uv_warp_compute(void *__restrict userdata,
|
|||
}
|
||||
}
|
||||
else {
|
||||
for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
|
||||
for (l = 0; l < mp->totloop; l++, mluv++) {
|
||||
uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,8 +83,12 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
if (mesh_in_a != nullptr) {
|
||||
meshes.append(mesh_in_a);
|
||||
transforms.append(nullptr);
|
||||
for (Material *material : Span(mesh_in_a->mat, mesh_in_a->totcol)) {
|
||||
materials.add(material);
|
||||
if (mesh_in_a->totcol == 0) {
|
||||
/* Necessary for faces using the default material when there are no material slots. */
|
||||
materials.add(nullptr);
|
||||
}
|
||||
else {
|
||||
materials.add_multiple({mesh_in_a->mat, mesh_in_a->totcol});
|
||||
}
|
||||
material_remaps.append({});
|
||||
}
|
||||
|
@ -98,20 +102,13 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
bke::geometry_set_gather_instances(geometry_set, set_groups);
|
||||
}
|
||||
|
||||
for (const bke::GeometryInstanceGroup &set_group : set_groups) {
|
||||
const Mesh *mesh = set_group.geometry_set.get_mesh_for_read();
|
||||
if (mesh != nullptr) {
|
||||
for (Material *material : Span(mesh->mat, mesh->totcol)) {
|
||||
materials.add(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const bke::GeometryInstanceGroup &set_group : set_groups) {
|
||||
const Mesh *mesh = set_group.geometry_set.get_mesh_for_read();
|
||||
if (mesh != nullptr) {
|
||||
Array<short> map(mesh->totcol);
|
||||
for (const int i : IndexRange(mesh->totcol)) {
|
||||
map[i] = materials.index_of(mesh->mat[i]);
|
||||
Material *material = mesh->mat[i];
|
||||
map[i] = material ? materials.index_of_or_add(material) : -1;
|
||||
}
|
||||
material_remaps.append(std::move(map));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
|
@ -126,7 +127,6 @@ static void copy_data_based_on_pairs(Span<T> data,
|
|||
* closest face.
|
||||
*/
|
||||
static void transfer_attributes(
|
||||
const Map<AttributeIDRef, AttributeKind> &attributes,
|
||||
const Span<VertexType> vertex_types,
|
||||
const bool keep_boundaries,
|
||||
const Span<int> new_to_old_edges_map,
|
||||
|
@ -135,12 +135,14 @@ static void transfer_attributes(
|
|||
const AttributeAccessor src_attributes,
|
||||
MutableAttributeAccessor dst_attributes)
|
||||
{
|
||||
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
GAttributeReader src_attribute = src_attributes.lookup(attribute_id);
|
||||
if (!src_attribute) {
|
||||
continue;
|
||||
}
|
||||
/* Retrieve all attributes except for position which is handled manually.
|
||||
* Remove anonymous attributes that don't need to be propagated.*/
|
||||
Set<AttributeIDRef> attribute_ids = src_attributes.all_ids();
|
||||
attribute_ids.remove("position");
|
||||
attribute_ids.remove_if([](const AttributeIDRef &id) { return !id.should_be_kept(); });
|
||||
|
||||
for (const AttributeIDRef &id : attribute_ids) {
|
||||
GAttributeReader src_attribute = src_attributes.lookup(id);
|
||||
|
||||
eAttrDomain out_domain;
|
||||
if (src_attribute.domain == ATTR_DOMAIN_FACE) {
|
||||
|
@ -156,7 +158,7 @@ static void transfer_attributes(
|
|||
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
|
||||
src_attribute.varray.type());
|
||||
GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
attribute_id, out_domain, data_type);
|
||||
id, out_domain, data_type);
|
||||
if (!dst_attribute) {
|
||||
continue;
|
||||
}
|
||||
|
@ -249,23 +251,6 @@ static void calc_boundaries(const Mesh &mesh,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the indices of the polygons connected to each vertex.
|
||||
*/
|
||||
static void create_vertex_poly_map(const Mesh &mesh,
|
||||
MutableSpan<Vector<int>> r_vertex_poly_indices)
|
||||
{
|
||||
const Span<MPoly> polys = mesh.polys();
|
||||
const Span<MLoop> loops = mesh.loops();
|
||||
for (const int i : polys.index_range()) {
|
||||
const MPoly &poly = polys[i];
|
||||
const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
|
||||
for (const MLoop &loop : poly_loops) {
|
||||
r_vertex_poly_indices[loop.v].append(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the polygons connected to the given vertex based on polygon adjacency. The ordering is
|
||||
* so such that the normals point in the same way as the original mesh. If the vertex is a
|
||||
|
@ -538,14 +523,13 @@ static bool vertex_needs_dissolving(const int vertex,
|
|||
const int first_poly_index,
|
||||
const int second_poly_index,
|
||||
const Span<VertexType> vertex_types,
|
||||
const Span<Vector<int>> vertex_poly_indices)
|
||||
const Span<Vector<int>> vert_to_poly_map)
|
||||
{
|
||||
/* Order is guaranteed to be the same because 2poly verts that are not on the boundary are
|
||||
* ignored in `sort_vertex_polys`. */
|
||||
return (vertex_types[vertex] != VertexType::Boundary &&
|
||||
vertex_poly_indices[vertex].size() == 2 &&
|
||||
vertex_poly_indices[vertex][0] == first_poly_index &&
|
||||
vertex_poly_indices[vertex][1] == second_poly_index);
|
||||
return (vertex_types[vertex] != VertexType::Boundary && vert_to_poly_map[vertex].size() == 2 &&
|
||||
vert_to_poly_map[vertex][0] == first_poly_index &&
|
||||
vert_to_poly_map[vertex][1] == second_poly_index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -558,7 +542,7 @@ static bool vertex_needs_dissolving(const int vertex,
|
|||
static void dissolve_redundant_verts(const Span<MEdge> edges,
|
||||
const Span<MPoly> polys,
|
||||
const Span<MLoop> loops,
|
||||
const Span<Vector<int>> vertex_poly_indices,
|
||||
const Span<Vector<int>> vert_to_poly_map,
|
||||
MutableSpan<VertexType> vertex_types,
|
||||
MutableSpan<int> old_to_new_edges_map,
|
||||
Vector<MEdge> &new_edges,
|
||||
|
@ -566,11 +550,11 @@ static void dissolve_redundant_verts(const Span<MEdge> edges,
|
|||
{
|
||||
const int vertex_num = vertex_types.size();
|
||||
for (const int vert_i : IndexRange(vertex_num)) {
|
||||
if (vertex_poly_indices[vert_i].size() != 2 || vertex_types[vert_i] != VertexType::Normal) {
|
||||
if (vert_to_poly_map[vert_i].size() != 2 || vertex_types[vert_i] != VertexType::Normal) {
|
||||
continue;
|
||||
}
|
||||
const int first_poly_index = vertex_poly_indices[vert_i][0];
|
||||
const int second_poly_index = vertex_poly_indices[vert_i][1];
|
||||
const int first_poly_index = vert_to_poly_map[vert_i][0];
|
||||
const int second_poly_index = vert_to_poly_map[vert_i][1];
|
||||
const int new_edge_index = new_edges.size();
|
||||
bool edge_created = false;
|
||||
const MPoly &poly = polys[first_poly_index];
|
||||
|
@ -581,13 +565,13 @@ static void dissolve_redundant_verts(const Span<MEdge> edges,
|
|||
const int v2 = edge.v2;
|
||||
bool mark_edge = false;
|
||||
if (vertex_needs_dissolving(
|
||||
v1, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
|
||||
v1, first_poly_index, second_poly_index, vertex_types, vert_to_poly_map)) {
|
||||
/* This vertex is now 'removed' and should be ignored elsewhere. */
|
||||
vertex_types[v1] = VertexType::Loose;
|
||||
mark_edge = true;
|
||||
}
|
||||
if (vertex_needs_dissolving(
|
||||
v2, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
|
||||
v2, first_poly_index, second_poly_index, vertex_types, vert_to_poly_map)) {
|
||||
/* This vertex is now 'removed' and should be ignored elsewhere. */
|
||||
vertex_types[v2] = VertexType::Loose;
|
||||
mark_edge = true;
|
||||
|
@ -622,38 +606,31 @@ static void dissolve_redundant_verts(const Span<MEdge> edges,
|
|||
*
|
||||
* Some special cases are needed for boundaries and non-manifold geometry.
|
||||
*/
|
||||
static void calc_dual_mesh(GeometrySet &geometry_set,
|
||||
const MeshComponent &in_component,
|
||||
const bool keep_boundaries)
|
||||
static Mesh *calc_dual_mesh(const Mesh &src_mesh, const bool keep_boundaries)
|
||||
{
|
||||
const Mesh &mesh_in = *in_component.get_for_read();
|
||||
const Span<MVert> src_verts = mesh_in.verts();
|
||||
const Span<MEdge> src_edges = mesh_in.edges();
|
||||
const Span<MPoly> src_polys = mesh_in.polys();
|
||||
const Span<MLoop> src_loops = mesh_in.loops();
|
||||
const Span<MVert> src_verts = src_mesh.verts();
|
||||
const Span<MEdge> src_edges = src_mesh.edges();
|
||||
const Span<MPoly> src_polys = src_mesh.polys();
|
||||
const Span<MLoop> src_loops = src_mesh.loops();
|
||||
|
||||
Map<AttributeIDRef, AttributeKind> attributes;
|
||||
geometry_set.gather_attributes_for_propagation(
|
||||
{GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_MESH, false, attributes);
|
||||
|
||||
Array<VertexType> vertex_types(mesh_in.totvert);
|
||||
Array<EdgeType> edge_types(mesh_in.totedge);
|
||||
calc_boundaries(mesh_in, vertex_types, edge_types);
|
||||
Array<VertexType> vertex_types(src_mesh.totvert);
|
||||
Array<EdgeType> edge_types(src_mesh.totedge);
|
||||
calc_boundaries(src_mesh, vertex_types, edge_types);
|
||||
/* Stores the indices of the polygons connected to the vertex. Because the polygons are looped
|
||||
* over in order of their indices, the polygon's indices will be sorted in ascending order.
|
||||
* (This can change once they are sorted using `sort_vertex_polys`). */
|
||||
Array<Vector<int>> vertex_poly_indices(mesh_in.totvert);
|
||||
Array<Array<int>> vertex_shared_edges(mesh_in.totvert);
|
||||
Array<Array<int>> vertex_corners(mesh_in.totvert);
|
||||
create_vertex_poly_map(mesh_in, vertex_poly_indices);
|
||||
threading::parallel_for(vertex_poly_indices.index_range(), 512, [&](IndexRange range) {
|
||||
Array<Vector<int>> vert_to_poly_map = bke::mesh_topology::build_vert_to_poly_map(
|
||||
src_polys, src_loops, src_verts.size());
|
||||
Array<Array<int>> vertex_shared_edges(src_mesh.totvert);
|
||||
Array<Array<int>> vertex_corners(src_mesh.totvert);
|
||||
threading::parallel_for(vert_to_poly_map.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
|
||||
(!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
|
||||
/* Bad vertex that we can't work with. */
|
||||
continue;
|
||||
}
|
||||
MutableSpan<int> loop_indices = vertex_poly_indices[i];
|
||||
MutableSpan<int> loop_indices = vert_to_poly_map[i];
|
||||
Array<int> sorted_corners(loop_indices.size());
|
||||
bool vertex_ok = true;
|
||||
if (vertex_types[i] == VertexType::Normal) {
|
||||
|
@ -692,8 +669,8 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
|
|||
}
|
||||
});
|
||||
|
||||
Vector<float3> vertex_positions(mesh_in.totpoly);
|
||||
for (const int i : IndexRange(mesh_in.totpoly)) {
|
||||
Vector<float3> vertex_positions(src_mesh.totpoly);
|
||||
for (const int i : IndexRange(src_mesh.totpoly)) {
|
||||
const MPoly &poly = src_polys[i];
|
||||
BKE_mesh_calc_poly_center(
|
||||
&poly, &src_loops[poly.loopstart], src_verts.data(), vertex_positions[i]);
|
||||
|
@ -702,9 +679,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
|
|||
Array<int> boundary_edge_midpoint_index;
|
||||
if (keep_boundaries) {
|
||||
/* Only initialize when we actually need it. */
|
||||
boundary_edge_midpoint_index.reinitialize(mesh_in.totedge);
|
||||
boundary_edge_midpoint_index.reinitialize(src_mesh.totedge);
|
||||
/* We need to add vertices at the centers of boundary edges. */
|
||||
for (const int i : IndexRange(mesh_in.totedge)) {
|
||||
for (const int i : IndexRange(src_mesh.totedge)) {
|
||||
if (edge_types[i] == EdgeType::Boundary) {
|
||||
float3 mid;
|
||||
const MEdge &edge = src_edges[i];
|
||||
|
@ -729,7 +706,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
|
|||
* needs to be created or not. If it's not -1 it gives the index in `new_edges` of the dual
|
||||
* edge. The edges coming from preserving the boundaries only get added once anyway, so we
|
||||
* don't need a hash-map for that. */
|
||||
Array<int> old_to_new_edges_map(mesh_in.totedge);
|
||||
Array<int> old_to_new_edges_map(src_mesh.totedge);
|
||||
old_to_new_edges_map.fill(-1);
|
||||
|
||||
/* This is necessary to prevent duplicate edges from being created, but will likely not do
|
||||
|
@ -737,20 +714,20 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
|
|||
dissolve_redundant_verts(src_edges,
|
||||
src_polys,
|
||||
src_loops,
|
||||
vertex_poly_indices,
|
||||
vert_to_poly_map,
|
||||
vertex_types,
|
||||
old_to_new_edges_map,
|
||||
new_edges,
|
||||
new_to_old_edges_map);
|
||||
|
||||
for (const int i : IndexRange(mesh_in.totvert)) {
|
||||
for (const int i : IndexRange(src_mesh.totvert)) {
|
||||
if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
|
||||
(!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
|
||||
/* Bad vertex that we can't work with. */
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector<int> loop_indices = vertex_poly_indices[i];
|
||||
Vector<int> loop_indices = vert_to_poly_map[i];
|
||||
Span<int> shared_edges = vertex_shared_edges[i];
|
||||
Span<int> sorted_corners = vertex_corners[i];
|
||||
if (vertex_types[i] == VertexType::Normal) {
|
||||
|
@ -904,13 +881,13 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
|
|||
}
|
||||
Mesh *mesh_out = BKE_mesh_new_nomain(
|
||||
vertex_positions.size(), new_edges.size(), 0, loops.size(), loop_lengths.size());
|
||||
transfer_attributes(attributes,
|
||||
vertex_types,
|
||||
|
||||
transfer_attributes(vertex_types,
|
||||
keep_boundaries,
|
||||
new_to_old_edges_map,
|
||||
new_to_old_face_corners_map,
|
||||
boundary_vertex_to_relevant_face_map,
|
||||
mesh_in.attributes(),
|
||||
src_mesh.attributes(),
|
||||
mesh_out->attributes_for_write());
|
||||
|
||||
MutableSpan<MVert> dst_verts = mesh_out->verts_for_write();
|
||||
|
@ -932,7 +909,7 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
|
|||
copy_v3_v3(dst_verts[i].co, vertex_positions[i]);
|
||||
}
|
||||
dst_edges.copy_from(new_edges);
|
||||
geometry_set.replace_mesh(mesh_out);
|
||||
return mesh_out;
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
@ -940,9 +917,9 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
|
||||
const bool keep_boundaries = params.extract_input<bool>("Keep Boundaries");
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
if (geometry_set.has_mesh()) {
|
||||
const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
|
||||
calc_dual_mesh(geometry_set, component, keep_boundaries);
|
||||
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
|
||||
Mesh *new_mesh = calc_dual_mesh(*mesh, keep_boundaries);
|
||||
geometry_set.replace_mesh(new_mesh);
|
||||
}
|
||||
});
|
||||
params.set_output("Dual Mesh", std::move(geometry_set));
|
||||
|
|
|
@ -255,7 +255,7 @@ int ConeConfig::calculate_total_corners()
|
|||
return corner_total;
|
||||
}
|
||||
|
||||
static void calculate_cone_verts(const MutableSpan<MVert> &verts, const ConeConfig &config)
|
||||
static void calculate_cone_verts(const ConeConfig &config, MutableSpan<MVert> verts)
|
||||
{
|
||||
Array<float2> circle(config.circle_segments);
|
||||
const float angle_delta = 2.0f * (M_PI / float(config.circle_segments));
|
||||
|
@ -319,7 +319,7 @@ static void calculate_cone_verts(const MutableSpan<MVert> &verts, const ConeConf
|
|||
}
|
||||
}
|
||||
|
||||
static void calculate_cone_edges(const MutableSpan<MEdge> &edges, const ConeConfig &config)
|
||||
static void calculate_cone_edges(const ConeConfig &config, MutableSpan<MEdge> edges)
|
||||
{
|
||||
int edge_index = 0;
|
||||
|
||||
|
@ -368,9 +368,9 @@ static void calculate_cone_edges(const MutableSpan<MEdge> &edges, const ConeConf
|
|||
}
|
||||
}
|
||||
|
||||
static void calculate_cone_faces(const MutableSpan<MLoop> &loops,
|
||||
const MutableSpan<MPoly> &polys,
|
||||
const ConeConfig &config)
|
||||
static void calculate_cone_faces(const ConeConfig &config,
|
||||
MutableSpan<MLoop> loops,
|
||||
MutableSpan<MPoly> polys)
|
||||
{
|
||||
int loop_index = 0;
|
||||
int poly_index = 0;
|
||||
|
@ -474,12 +474,10 @@ static void calculate_cone_faces(const MutableSpan<MLoop> &loops,
|
|||
}
|
||||
}
|
||||
|
||||
static void calculate_selection_outputs(Mesh *mesh,
|
||||
const ConeConfig &config,
|
||||
ConeAttributeOutputs &attribute_outputs)
|
||||
static void calculate_selection_outputs(const ConeConfig &config,
|
||||
const ConeAttributeOutputs &attribute_outputs,
|
||||
MutableAttributeAccessor attributes)
|
||||
{
|
||||
MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
|
||||
/* Populate "Top" selection output. */
|
||||
if (attribute_outputs.top_id) {
|
||||
const bool face = !config.top_is_point && config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
|
||||
|
@ -691,11 +689,11 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
|
|||
MutableSpan<MPoly> polys = mesh->polys_for_write();
|
||||
MutableSpan<MLoop> loops = mesh->loops_for_write();
|
||||
|
||||
calculate_cone_verts(verts, config);
|
||||
calculate_cone_edges(edges, config);
|
||||
calculate_cone_faces(loops, polys, config);
|
||||
calculate_cone_verts(config, verts);
|
||||
calculate_cone_edges(config, edges);
|
||||
calculate_cone_faces(config, loops, polys);
|
||||
calculate_cone_uvs(mesh, config);
|
||||
calculate_selection_outputs(mesh, config, attribute_outputs);
|
||||
calculate_selection_outputs(config, attribute_outputs, mesh->attributes_for_write());
|
||||
|
||||
mesh->loose_edges_tag_none();
|
||||
|
||||
|
|
|
@ -170,6 +170,13 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
|
||||
Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh);
|
||||
|
||||
if (use_creases) {
|
||||
/* Remove the layer in case it was created by the node from the field input. The fact
|
||||
* that this node uses #CD_CREASE to input creases to the subvision code is meant to be
|
||||
* an implementation detail ideally. */
|
||||
CustomData_free_layers(&mesh_out->edata, CD_CREASE, mesh_out->totedge);
|
||||
}
|
||||
|
||||
geometry_set.replace_mesh(mesh_out);
|
||||
|
||||
BKE_subdiv_free(subdiv);
|
||||
|
|
|
@ -674,15 +674,8 @@ static void get_ccgdm_data(DerivedMesh *lodm,
|
|||
|
||||
mpoly = lodm->getPolyArray(lodm) + poly_index;
|
||||
g_index = grid_offset[poly_index];
|
||||
S = mdisp_rot_face_to_crn(lodm->getVertArray(lodm),
|
||||
mpoly,
|
||||
lodm->getLoopArray(lodm),
|
||||
lt,
|
||||
face_side,
|
||||
u * (face_side - 1),
|
||||
v * (face_side - 1),
|
||||
&crn_x,
|
||||
&crn_y);
|
||||
S = mdisp_rot_face_to_crn(
|
||||
mpoly, face_side, u * (face_side - 1), v * (face_side - 1), &crn_x, &crn_y);
|
||||
}
|
||||
else {
|
||||
/* number of faces per grid side */
|
||||
|
|
|
@ -117,9 +117,10 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
|
|||
return;
|
||||
}
|
||||
|
||||
/* Meta strips requires special handling: their content is to be translated, and then frame range
|
||||
* of the meta is to be updated for the updated content. */
|
||||
if (seq->type == SEQ_TYPE_META) {
|
||||
/* Meta strips requires their content is to be translated, and then frame range of the meta is
|
||||
* updated based on nested strips. Thiw won't work for empty metas, so they can be treated as
|
||||
* normal strip. */
|
||||
if (seq->type == SEQ_TYPE_META && !BLI_listbase_is_empty(&seq->seqbase)) {
|
||||
Sequence *seq_child;
|
||||
for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
|
||||
SEQ_transform_translate_sequence(evil_scene, seq_child, delta);
|
||||
|
|
Loading…
Reference in New Issue