Merge branch 'refactor-mesh-position-generic' into refactor-mesh-corners-generic
This commit is contained in:
commit
8e2dae3f8d
|
@ -12,7 +12,6 @@ if(UNIX)
|
|||
automake
|
||||
bison
|
||||
${_libtoolize_name}
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
tclsh
|
||||
|
|
|
@ -26,5 +26,6 @@ endif()
|
|||
|
||||
add_dependencies(
|
||||
external_epoxy
|
||||
# Needed for `MESON`.
|
||||
external_python_site_packages
|
||||
)
|
||||
|
|
|
@ -18,6 +18,7 @@ ExternalProject_Add(external_fribidi
|
|||
add_dependencies(
|
||||
external_fribidi
|
||||
external_python
|
||||
# Needed for `MESON`.
|
||||
external_python_site_packages
|
||||
)
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ if(WIN32)
|
|||
set(HARFBUZZ_PKG_ENV FREETYPE_DIR=${LIBDIR}/freetype)
|
||||
else()
|
||||
set(HARFBUZZ_CONFIGURE_ENV ${CONFIGURE_ENV})
|
||||
set(HARFBUZZ_PKG_ENV PKG_CONFIG_PATH=${LIBDIR}/freetype/lib/pkgconfig:${LIBDIR}/brotli/lib/pkgconfig:$PKG_CONFIG_PATH)
|
||||
set(HARFBUZZ_PKG_ENV PKG_CONFIG_PATH=${LIBDIR}/freetype/lib/pkgconfig:${LIBDIR}/brotli/lib/pkgconfig:${LIBDIR}/lib/python3.10/pkgconfig:$PKG_CONFIG_PATH)
|
||||
endif()
|
||||
|
||||
set(HARFBUZZ_EXTRA_OPTIONS
|
||||
|
@ -13,6 +13,9 @@ set(HARFBUZZ_EXTRA_OPTIONS
|
|||
-Dfreetype=enabled
|
||||
-Dglib=disabled
|
||||
-Dgobject=disabled
|
||||
# Only used for command line utilities,
|
||||
# disable as this would add an addition & unnecessary build-dependency.
|
||||
-Dcairo=disabled
|
||||
)
|
||||
|
||||
ExternalProject_Add(external_harfbuzz
|
||||
|
@ -30,6 +33,7 @@ ExternalProject_Add(external_harfbuzz
|
|||
add_dependencies(
|
||||
external_harfbuzz
|
||||
external_python
|
||||
# Needed for `MESON`.
|
||||
external_python_site_packages
|
||||
)
|
||||
|
||||
|
|
|
@ -268,6 +268,10 @@ harvest(haru/include haru/include "*.h")
|
|||
harvest(haru/lib haru/lib "*.a")
|
||||
harvest(zstd/include zstd/include "*.h")
|
||||
harvest(zstd/lib zstd/lib "*.a")
|
||||
harvest(shaderc shaderc "*")
|
||||
harvest(vulkan_headers vulkan "*")
|
||||
harvest_rpath_lib(vulkan_loader/lib vulkan/lib "*${SHAREDLIBEXT}*")
|
||||
harvest(vulkan_loader/loader vulkan/loader "*")
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
harvest(libglu/lib mesa/lib "*${SHAREDLIBEXT}*")
|
||||
|
|
|
@ -33,6 +33,8 @@ set(MESA_EXTRA_FLAGS
|
|||
# At some point we will likely want to support Wayland.
|
||||
# Disable for now since it's not officially supported.
|
||||
-Dplatforms=x11
|
||||
# Needed to find the local expat.
|
||||
--pkg-config-path=${LIBDIR}/expat/lib/pkgconfig
|
||||
--native-file ${BUILD_DIR}/mesa/tmp/native-file.ini
|
||||
)
|
||||
|
||||
|
@ -53,4 +55,8 @@ add_dependencies(
|
|||
external_mesa
|
||||
ll
|
||||
external_zlib
|
||||
# Run-time dependency.
|
||||
external_expat
|
||||
# Needed for `MESON`.
|
||||
external_python_site_packages
|
||||
)
|
||||
|
|
|
@ -117,7 +117,7 @@ else()
|
|||
set(LIBEXT ".a")
|
||||
set(LIBPREFIX "lib")
|
||||
set(MESON ${LIBDIR}/python/bin/meson)
|
||||
if(APPLE)
|
||||
if(APPLE)
|
||||
set(SHAREDLIBEXT ".dylib")
|
||||
|
||||
# Use same Xcode detection as Blender itself.
|
||||
|
|
|
@ -5,7 +5,11 @@ if(WIN32 AND BUILD_MODE STREQUAL Debug)
|
|||
# zstandard is determined to build and link release mode libs in a debug
|
||||
# configuration, the only way to make it happy is to bend to its will
|
||||
# and give it a library to link with.
|
||||
set(PIP_CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.lib ${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib)
|
||||
set(
|
||||
PIP_CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.lib
|
||||
${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib
|
||||
)
|
||||
else()
|
||||
set(PIP_CONFIGURE_COMMAND echo ".")
|
||||
endif()
|
||||
|
@ -15,9 +19,23 @@ ExternalProject_Add(external_python_site_packages
|
|||
CONFIGURE_COMMAND ${PIP_CONFIGURE_COMMAND}
|
||||
BUILD_COMMAND ""
|
||||
PREFIX ${BUILD_DIR}/site_packages
|
||||
# setuptools is downgraded to 63.2.0 (same as python 3.10.8) since numpy 1.23.x seemingly has
|
||||
|
||||
# setuptools is downgraded to 63.2.0 (same as python 3.10.8) since numpy 1.23.x seemingly has
|
||||
# issues building on windows with the newer versions that ships with python 3.10.9+
|
||||
INSTALL_COMMAND ${PYTHON_BINARY} -m pip install --no-cache-dir ${SITE_PACKAGES_EXTRA} setuptools==63.2.0 cython==${CYTHON_VERSION} idna==${IDNA_VERSION} charset-normalizer==${CHARSET_NORMALIZER_VERSION} urllib3==${URLLIB3_VERSION} certifi==${CERTIFI_VERSION} requests==${REQUESTS_VERSION} zstandard==${ZSTANDARD_VERSION} autopep8==${AUTOPEP8_VERSION} pycodestyle==${PYCODESTYLE_VERSION} toml==${TOML_VERSION} meson==${MESON_VERSION} --no-binary :all:
|
||||
INSTALL_COMMAND ${PYTHON_BINARY} -m pip install --no-cache-dir ${SITE_PACKAGES_EXTRA}
|
||||
setuptools==63.2.0
|
||||
cython==${CYTHON_VERSION}
|
||||
idna==${IDNA_VERSION}
|
||||
charset-normalizer==${CHARSET_NORMALIZER_VERSION}
|
||||
urllib3==${URLLIB3_VERSION}
|
||||
certifi==${CERTIFI_VERSION}
|
||||
requests==${REQUESTS_VERSION}
|
||||
zstandard==${ZSTANDARD_VERSION}
|
||||
autopep8==${AUTOPEP8_VERSION}
|
||||
pycodestyle==${PYCODESTYLE_VERSION}
|
||||
toml==${TOML_VERSION}
|
||||
meson==${MESON_VERSION}
|
||||
--no-binary :all:
|
||||
)
|
||||
|
||||
if(USE_PIP_NUMPY)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(SNDFILE_EXTRA_ARGS)
|
||||
set(SNDFILE_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/ogg/lib/pkgconfig:${mingw_LIBDIR}/vorbis/lib/pkgconfig:${mingw_LIBDIR}/flac/lib/pkgconfig:${mingw_LIBDIR}/opus/lib/pkgconfig:${mingw_LIBDIR})
|
||||
set(SNDFILE_ENV)
|
||||
|
||||
if(WIN32)
|
||||
set(SNDFILE_ENV PKG_CONFIG_PATH=${mingw_LIBDIR}/ogg/lib/pkgconfig:${mingw_LIBDIR}/vorbis/lib/pkgconfig:${mingw_LIBDIR}/flac/lib/pkgconfig:${mingw_LIBDIR}/opus/lib/pkgconfig:${mingw_LIBDIR})
|
||||
set(SNDFILE_ENV set ${SNDFILE_ENV} &&)
|
||||
# Shared for windows because static libs will drag in a libgcc dependency.
|
||||
set(SNDFILE_OPTIONS --disable-static --enable-shared )
|
||||
|
@ -11,6 +12,16 @@ else()
|
|||
set(SNDFILE_OPTIONS --enable-static --disable-shared )
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
# NOTE(@campbellbarton): For some reason OPUS is alone in referencing the sub-directory,
|
||||
# manipulate the package-config file to prevent this from happening.
|
||||
# There is no problem with applying this change multiple times.
|
||||
#
|
||||
# Replace: Cflags: -I${includedir}/opus
|
||||
# With: Cflags: -I${includedir}
|
||||
set(SNDFILE_ENV sed -i s/{includedir}\\/opus/{includedir}/g ${LIBDIR}/opus/lib/pkgconfig/opus.pc && ${SNDFILE_ENV})
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(external_sndfile
|
||||
URL file://${PACKAGE_DIR}/${SNDFILE_FILE}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
|
|
|
@ -195,15 +195,18 @@ set(TIFF_HASH_TYPE MD5)
|
|||
set(TIFF_FILE tiff-${TIFF_VERSION}.tar.gz)
|
||||
set(TIFF_CPE "cpe:2.3:a:libtiff:libtiff:${TIFF_VERSION}:*:*:*:*:*:*:*")
|
||||
|
||||
set(OSL_VERSION 1.12.7.1)
|
||||
set(OSL_URI https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/archive/v${OSL_VERSION}.tar.gz)
|
||||
set(OSL_HASH 53211da86c34ba6e0344998c1a6d219c)
|
||||
# Recent commit from 1.13.0.2 under development, which includes string table
|
||||
# changes that make the Cycles OptiX implementation work. Official 1.12 OSL
|
||||
# releases should also build but without OptiX support.
|
||||
set(OSL_VERSION 1a7670600c8b08c2443a78d03c8c27e9a1149140)
|
||||
set(OSL_URI https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/archive/${OSL_VERSION}.tar.gz)
|
||||
set(OSL_HASH 7b6d6716b05d1addb92a8f47280bf77f)
|
||||
set(OSL_HASH_TYPE MD5)
|
||||
set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz)
|
||||
|
||||
# NOTE: When updating the python version, it's required to check the versions of
|
||||
# it wants to use in PCbuild/get_externals.bat for the following dependencies:
|
||||
# BZIP2, FFI, SQLITE and change the versions in this file as well. For compliance
|
||||
# BZIP2, FFI, SQLITE and change the versions in this file as well. For compliance
|
||||
# reasons there can be no exceptions to this.
|
||||
|
||||
set(PYTHON_VERSION 3.10.9)
|
||||
|
@ -229,20 +232,34 @@ set(OPENVDB_HASH 64301c737e16b26c8f3085a31e6397e9)
|
|||
set(OPENVDB_HASH_TYPE MD5)
|
||||
set(OPENVDB_FILE openvdb-${OPENVDB_VERSION}.tar.gz)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Python Modules
|
||||
|
||||
# Needed by: TODO.
|
||||
set(IDNA_VERSION 3.3)
|
||||
# Needed by: TODO.
|
||||
set(CHARSET_NORMALIZER_VERSION 2.0.10)
|
||||
# Needed by: TODO.
|
||||
set(URLLIB3_VERSION 1.26.8)
|
||||
set(URLLIB3_CPE "cpe:2.3:a:urllib3:urllib3:${URLLIB3_VERSION}:*:*:*:*:*:*:*")
|
||||
# Needed by: Python's `requests` module (so add-ons can authenticate against trusted certificates).
|
||||
set(CERTIFI_VERSION 2021.10.8)
|
||||
# Needed by: Some of Blender's add-ons (to support convenient interaction with online services).
|
||||
set(REQUESTS_VERSION 2.27.1)
|
||||
# Needed by: Python's `numpy` module (used by some add-ons).
|
||||
set(CYTHON_VERSION 0.29.30)
|
||||
# The version of the zstd library used to build the Python package should match ZSTD_VERSION
|
||||
# Needed by: Python scripts that read `.blend` files, as files may use Z-standard compression.
|
||||
# The version of the ZSTD library used to build the Python package should match ZSTD_VERSION
|
||||
# defined below. At this time of writing, 0.17.0 was already released,
|
||||
# but built against zstd 1.5.1, while we use 1.5.0.
|
||||
# but built against ZSTD 1.5.1, while we use 1.5.0.
|
||||
set(ZSTANDARD_VERSION 0.16.0)
|
||||
# Auto-format Python source (developer tool, not used by Blender at run-time).
|
||||
set(AUTOPEP8_VERSION 1.6.0)
|
||||
# Needed by: `autopep8` (so the version doesn't change on rebuild).
|
||||
set(PYCODESTYLE_VERSION 2.8.0)
|
||||
# Needed by: `autopep8` (so the version doesn't change on rebuild).
|
||||
set(TOML_VERSION 0.10.2)
|
||||
# Build system for other packages (not used by Blender at run-time).
|
||||
set(MESON_VERSION 0.63.0)
|
||||
|
||||
set(NUMPY_VERSION 1.23.5)
|
||||
|
|
|
@ -30,6 +30,17 @@ set(VULKAN_LOADER_EXTRA_ARGS
|
|||
-DVULKAN_HEADERS_INSTALL_DIR=${LIBDIR}/vulkan_headers
|
||||
)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
# These are used in `cmake/FindWayland.cmake` from `external_vulkan_loader`.
|
||||
# NOTE: When upgrading to CMAKE 3.22 we it would be cleaner to use: `PKG_CONFIG_ARGN`,
|
||||
# so `pkgconfig` would find wayland.
|
||||
set(VULKAN_LOADER_EXTRA_ARGS
|
||||
${VULKAN_LOADER_EXTRA_ARGS}
|
||||
-DPKG_WAYLAND_INCLUDE_DIRS=${LIBDIR}/wayland/include
|
||||
-DPKG_WAYLAND_LIBRARY_DIRS=${LIBDIR}/wayland/lib64
|
||||
)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(external_vulkan_loader
|
||||
URL file://${PACKAGE_DIR}/${VULKAN_LOADER_FILE}
|
||||
URL_HASH ${VULKAN_LOADER_HASH_TYPE}=${VULKAN_LOADER_HASH}
|
||||
|
@ -43,7 +54,12 @@ add_dependencies(
|
|||
external_vulkan_headers
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
if(UNIX AND NOT APPLE)
|
||||
add_dependencies(
|
||||
external_vulkan_loader
|
||||
external_wayland
|
||||
)
|
||||
elseif(WIN32)
|
||||
if(BUILD_MODE STREQUAL Release)
|
||||
ExternalProject_Add_Step(external_vulkan_loader after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/vulkan_loader/ ${HARVEST_TARGET}/vulkan
|
||||
|
|
|
@ -5,7 +5,6 @@ ExternalProject_Add(external_wayland
|
|||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
URL_HASH ${WAYLAND_HASH_TYPE}=${WAYLAND_HASH}
|
||||
PREFIX ${BUILD_DIR}/wayland
|
||||
PATCH_COMMAND ${PATCH_CMD} -d ${BUILD_DIR}/wayland/src/external_wayland < ${PATCH_DIR}/wayland.diff
|
||||
# Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own LIBEXPAT & LIBXML2.
|
||||
#
|
||||
# NOTE: passing link args "ffi/lib" should not be needed, but
|
||||
|
@ -24,4 +23,7 @@ add_dependencies(
|
|||
external_expat
|
||||
external_xml2
|
||||
external_ffi
|
||||
|
||||
# Needed for `MESON`.
|
||||
external_python_site_packages
|
||||
)
|
||||
|
|
|
@ -15,4 +15,6 @@ ExternalProject_Add(external_wayland_protocols
|
|||
add_dependencies(
|
||||
external_wayland_protocols
|
||||
external_wayland
|
||||
# Needed for `MESON`.
|
||||
external_python_site_packages
|
||||
)
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
--- meson.build.orig 2022-06-30 22:59:11.000000000 +0100
|
||||
+++ meson.build 2022-09-27 13:21:26.428517668 +0100
|
||||
@@ -2,7 +2,7 @@
|
||||
'wayland', 'c',
|
||||
version: '1.21.0',
|
||||
license: 'MIT',
|
||||
- meson_version: '>= 0.56.0',
|
||||
+ meson_version: '>= 0.55.1',
|
||||
default_options: [
|
||||
'warning_level=2',
|
||||
'buildtype=debugoptimized',
|
|
@ -105,9 +105,10 @@ if(WITH_VULKAN_BACKEND)
|
|||
set(VULKAN_ROOT_DIR ${LIBDIR}/vulkan/macOS)
|
||||
set(VULKAN_INCLUDE_DIR ${VULKAN_ROOT_DIR}/include)
|
||||
set(VULKAN_LIBRARY ${VULKAN_ROOT_DIR}/lib/libvulkan.1.dylib)
|
||||
set(SHADERC_LIBRARY ${VULKAN_ROOT_DIR}/lib/libshaderc_combined.a)
|
||||
|
||||
set(VULKAN_INCLUDE_DIRS ${VULKAN_INCLUDE_DIR} ${MOLTENVK_INCLUDE_DIRS})
|
||||
set(VULKAN_LIBRARIES ${VULKAN_LIBRARY} ${MOLTENVK_LIBRARIES})
|
||||
set(VULKAN_LIBRARIES ${VULKAN_LIBRARY} ${SHADERC_LIBRARY} ${MOLTENVK_LIBRARIES})
|
||||
else()
|
||||
message(WARNING "Vulkan SDK was not found, disabling WITH_VULKAN_BACKEND")
|
||||
set(WITH_VULKAN_BACKEND OFF)
|
||||
|
|
|
@ -163,10 +163,10 @@ void device_hip_info(vector<DeviceInfo> &devices)
|
|||
/* If device has a kernel timeout and no compute preemption, we assume
|
||||
* it is connected to a display and will freeze the display while doing
|
||||
* computations. */
|
||||
int timeout_attr = 0, preempt_attr = 0;
|
||||
int timeout_attr = 0;
|
||||
hipDeviceGetAttribute(&timeout_attr, hipDeviceAttributeKernelExecTimeout, num);
|
||||
|
||||
if (timeout_attr && !preempt_attr) {
|
||||
if (timeout_attr) {
|
||||
VLOG_INFO << "Device is recognized as display.";
|
||||
info.description += " (Display)";
|
||||
info.display_device = true;
|
||||
|
|
|
@ -26,9 +26,12 @@ class HdCyclesVolumeLoader : public VDBImageLoader {
|
|||
HdCyclesVolumeLoader(const std::string &filePath, const std::string &gridName)
|
||||
: VDBImageLoader(gridName)
|
||||
{
|
||||
/* Disably delay loading and file copying, this has poor performance
|
||||
* on network drivers. */
|
||||
const bool delay_load = false;
|
||||
openvdb::io::File file(filePath);
|
||||
file.setCopyMaxBytes(0);
|
||||
if (file.open()) {
|
||||
if (file.open(delay_load)) {
|
||||
grid = file.readGrid(gridName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -255,8 +255,9 @@ ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
|
|||
float3 inplane;
|
||||
|
||||
if (in_volume_segment) {
|
||||
/* FIXME: handle rectangular light. */
|
||||
inplane = ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, randu, randv);
|
||||
inplane = sample_rectangle ?
|
||||
rectangle_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, randu, randv) :
|
||||
ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, randu, randv);
|
||||
ls->P += inplane;
|
||||
ls->pdf = invarea;
|
||||
}
|
||||
|
|
|
@ -30,8 +30,13 @@ typedef struct LightSample {
|
|||
|
||||
ccl_device_inline float3 ellipse_sample(float3 ru, float3 rv, float randu, float randv)
|
||||
{
|
||||
to_unit_disk(&randu, &randv);
|
||||
return ru * randu + rv * randv;
|
||||
const float2 rand = concentric_sample_disk(randu, randv);
|
||||
return ru * rand.x + rv * rand.y;
|
||||
}
|
||||
|
||||
ccl_device_inline float3 rectangle_sample(float3 ru, float3 rv, float randu, float randv)
|
||||
{
|
||||
return ru * (2.0f * randu - 1.0f) + rv * (2.0f * randv - 1.0f);
|
||||
}
|
||||
|
||||
ccl_device float3 disk_light_sample(float3 v, float randu, float randv)
|
||||
|
|
|
@ -59,41 +59,9 @@ ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
|
|||
{
|
||||
/* Sample light index from distribution. */
|
||||
const int index = light_distribution_sample(kg, &randu);
|
||||
ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(light_distribution,
|
||||
index);
|
||||
const int prim = kdistribution->prim;
|
||||
|
||||
if (prim >= 0) {
|
||||
/* Mesh light. */
|
||||
const int object = kdistribution->mesh_light.object_id;
|
||||
|
||||
/* Exclude synthetic meshes from shadow catcher pass. */
|
||||
if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
|
||||
!(kernel_data_fetch(object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int shader_flag = kdistribution->mesh_light.shader_flag;
|
||||
if (!triangle_light_sample<in_volume_segment>(kg, prim, object, randu, randv, time, ls, P)) {
|
||||
return false;
|
||||
}
|
||||
ls->shader |= shader_flag;
|
||||
}
|
||||
else {
|
||||
const int lamp = -prim - 1;
|
||||
|
||||
if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls)) {
|
||||
return false;
|
||||
}
|
||||
ls->pdf_selection = kernel_data.integrator.distribution_pdf_lights;
|
||||
}
|
||||
|
||||
ls->pdf *= ls->pdf_selection;
|
||||
return (ls->pdf > 0.0f);
|
||||
const float pdf_selection = kernel_data.integrator.distribution_pdf_lights;
|
||||
return light_sample<in_volume_segment>(
|
||||
kg, randu, randv, time, P, bounce, path_flag, index, pdf_selection, ls);
|
||||
}
|
||||
|
||||
ccl_device_inline float light_distribution_pdf_lamp(KernelGlobals kg)
|
||||
|
|
|
@ -14,6 +14,13 @@
|
|||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Light info. */
|
||||
|
||||
ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce)
|
||||
{
|
||||
return (bounce > kernel_data_fetch(lights, index).max_bounces);
|
||||
}
|
||||
|
||||
/* Sample point on an individual light. */
|
||||
|
||||
template<bool in_volume_segment>
|
||||
|
@ -90,6 +97,68 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
|
|||
return in_volume_segment || (ls->pdf > 0.0f);
|
||||
}
|
||||
|
||||
/* Sample a point on the chosen emitter. */
|
||||
|
||||
template<bool in_volume_segment>
|
||||
ccl_device_noinline bool light_sample(KernelGlobals kg,
|
||||
const float randu,
|
||||
const float randv,
|
||||
const float time,
|
||||
const float3 P,
|
||||
const int bounce,
|
||||
const uint32_t path_flag,
|
||||
const int emitter_index,
|
||||
const float pdf_selection,
|
||||
ccl_private LightSample *ls)
|
||||
{
|
||||
int prim;
|
||||
MeshLight mesh_light;
|
||||
if (kernel_data.integrator.use_light_tree) {
|
||||
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
|
||||
emitter_index);
|
||||
prim = kemitter->prim;
|
||||
mesh_light = kemitter->mesh_light;
|
||||
}
|
||||
else {
|
||||
ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(
|
||||
light_distribution, emitter_index);
|
||||
prim = kdistribution->prim;
|
||||
mesh_light = kdistribution->mesh_light;
|
||||
}
|
||||
|
||||
/* A different value would be assigned in `triangle_light_sample()` if `!use_light_tree`. */
|
||||
ls->pdf_selection = pdf_selection;
|
||||
|
||||
if (prim >= 0) {
|
||||
/* Mesh light. */
|
||||
const int object = mesh_light.object_id;
|
||||
|
||||
/* Exclude synthetic meshes from shadow catcher pass. */
|
||||
if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
|
||||
!(kernel_data_fetch(object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int shader_flag = mesh_light.shader_flag;
|
||||
if (!triangle_light_sample<in_volume_segment>(kg, prim, object, randu, randv, time, ls, P)) {
|
||||
return false;
|
||||
}
|
||||
ls->shader |= shader_flag;
|
||||
}
|
||||
else {
|
||||
if (UNLIKELY(light_select_reached_max_bounces(kg, ~prim, bounce))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!light_sample<in_volume_segment>(kg, ~prim, randu, randv, P, path_flag, ls)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ls->pdf *= ls->pdf_selection;
|
||||
return in_volume_segment || (ls->pdf > 0.0f);
|
||||
}
|
||||
|
||||
/* Intersect ray with individual light. */
|
||||
|
||||
ccl_device bool lights_intersect(KernelGlobals kg,
|
||||
|
@ -230,11 +299,4 @@ ccl_device_forceinline void light_update_position(KernelGlobals kg,
|
|||
}
|
||||
}
|
||||
|
||||
/* Light info. */
|
||||
|
||||
ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce)
|
||||
{
|
||||
return (bounce > kernel_data_fetch(lights, index).max_bounces);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -22,16 +22,15 @@
|
|||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* TODO: this seems like a relative expensive computation, and we can make it a lot cheaper
|
||||
* by using a bounding sphere instead of a bounding box. This will be more inaccurate, but it
|
||||
* might be fine when used along with the adaptive splitting. */
|
||||
/* TODO: this seems like a relative expensive computation. We can make it a lot cheaper by using a
|
||||
* bounding sphere instead of a bounding box, but this will reduce the accuracy sometimes. */
|
||||
ccl_device float light_tree_cos_bounding_box_angle(const BoundingBox bbox,
|
||||
const float3 P,
|
||||
const float3 point_to_centroid)
|
||||
{
|
||||
if (P.x > bbox.min.x && P.y > bbox.min.y && P.z > bbox.min.z && P.x < bbox.max.x &&
|
||||
P.y < bbox.max.y && P.z < bbox.max.z) {
|
||||
/* If P is inside the bbox, `theta_u` covers the whole sphere */
|
||||
/* If P is inside the bbox, `theta_u` covers the whole sphere. */
|
||||
return -1.0f;
|
||||
}
|
||||
float cos_theta_u = 1.0f;
|
||||
|
@ -53,7 +52,7 @@ ccl_device_forceinline float sin_from_cos(const float c)
|
|||
return safe_sqrtf(1.0f - sqr(c));
|
||||
}
|
||||
|
||||
/* Compute vector v as in Fig .8. P_v is the corresponding point along the ray ccl_device float3 */
|
||||
/* Compute vector v as in Fig .8. P_v is the corresponding point along the ray. */
|
||||
ccl_device float3 compute_v(
|
||||
const float3 centroid, const float3 P, const float3 D, const float3 bcone_axis, const float t)
|
||||
{
|
||||
|
@ -95,12 +94,12 @@ ccl_device void light_tree_importance(const float3 N_or_D,
|
|||
|
||||
const float sin_theta_u = sin_from_cos(cos_theta_u);
|
||||
|
||||
/* cos(theta_i') in the paper, omitted for volume */
|
||||
/* cos(theta_i') in the paper, omitted for volume. */
|
||||
float cos_min_incidence_angle = 1.0f;
|
||||
float cos_max_incidence_angle = 1.0f;
|
||||
|
||||
/* when sampling the light tree for the second time in `shade_volume.h` and when query the pdf in
|
||||
* `sample.h` */
|
||||
/* When sampling the light tree for the second time in `shade_volume.h` and when query the pdf in
|
||||
* `sample.h`. */
|
||||
const bool in_volume = is_zero(N_or_D);
|
||||
if (!in_volume_segment && !in_volume) {
|
||||
const float3 N = N_or_D;
|
||||
|
@ -116,7 +115,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
|
|||
/* If the node is guaranteed to be behind the surface we're sampling, and the surface is
|
||||
* opaque, then we can give the node an importance of 0 as it contributes nothing to the
|
||||
* surface. This is more accurate than the bbox test if we are calculating the importance of
|
||||
* an emitter with radius */
|
||||
* an emitter with radius. */
|
||||
if (!has_transmission && cos_min_incidence_angle < 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -133,8 +132,8 @@ ccl_device void light_tree_importance(const float3 N_or_D,
|
|||
float cos_theta_o, sin_theta_o;
|
||||
fast_sincosf(bcone.theta_o, &sin_theta_o, &cos_theta_o);
|
||||
|
||||
/* minimum angle an emitter’s axis would form with the direction to the shading point,
|
||||
* cos(theta') in the paper */
|
||||
/* Minimum angle an emitter’s axis would form with the direction to the shading point,
|
||||
* cos(theta') in the paper. */
|
||||
float cos_min_outgoing_angle;
|
||||
if ((cos_theta >= cos_theta_u) || (cos_theta_minus_theta_u >= cos_theta_o)) {
|
||||
/* theta - theta_o - theta_u <= 0 */
|
||||
|
@ -151,7 +150,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
|
|||
sin_theta_minus_theta_u * sin_theta_o;
|
||||
}
|
||||
else {
|
||||
/* cluster invisible */
|
||||
/* Cluster is invisible. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -190,7 +189,7 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
|
|||
ccl_private float3 ¢roid,
|
||||
ccl_private packed_float3 &dir)
|
||||
{
|
||||
const int prim_id = kemitter->prim_id;
|
||||
const int prim_id = kemitter->prim;
|
||||
if (prim_id < 0) {
|
||||
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ~prim_id);
|
||||
centroid = klight->co;
|
||||
|
@ -200,14 +199,14 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
|
|||
dir = klight->spot.dir;
|
||||
break;
|
||||
case LIGHT_POINT:
|
||||
/* Disk-oriented normal */
|
||||
/* Disk-oriented normal. */
|
||||
dir = safe_normalize(P - centroid);
|
||||
break;
|
||||
case LIGHT_AREA:
|
||||
dir = klight->area.dir;
|
||||
break;
|
||||
case LIGHT_BACKGROUND:
|
||||
/* Aarbitrary centroid and direction */
|
||||
/* Arbitrary centroid and direction. */
|
||||
centroid = make_float3(0.0f, 0.0f, 1.0f);
|
||||
dir = make_float3(0.0f, 0.0f, -1.0f);
|
||||
return !in_volume_segment;
|
||||
|
@ -224,14 +223,14 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
|
|||
triangle_world_space_vertices(kg, object, prim_id, -1.0f, vertices);
|
||||
centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
|
||||
|
||||
if (kemitter->mesh_light.emission_sampling == EMISSION_SAMPLING_FRONT) {
|
||||
if (kemitter->emission_sampling == EMISSION_SAMPLING_FRONT) {
|
||||
dir = safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0]));
|
||||
}
|
||||
else if (kemitter->mesh_light.emission_sampling == EMISSION_SAMPLING_BACK) {
|
||||
else if (kemitter->emission_sampling == EMISSION_SAMPLING_BACK) {
|
||||
dir = -safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0]));
|
||||
}
|
||||
else {
|
||||
/* Double sided: any vector in the plane. */
|
||||
/* Double-sided: any vector in the plane. */
|
||||
dir = safe_normalize(vertices[0] - vertices[1]);
|
||||
}
|
||||
}
|
||||
|
@ -265,13 +264,13 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
|
|||
return;
|
||||
}
|
||||
|
||||
const int prim_id = kemitter->prim_id;
|
||||
const int prim_id = kemitter->prim;
|
||||
|
||||
if (in_volume_segment) {
|
||||
const float3 D = N_or_D;
|
||||
/* Closest point */
|
||||
/* Closest point. */
|
||||
P_c = P + dot(centroid - P, D) * D;
|
||||
/* minimal distance of the ray to the cluster */
|
||||
/* Minimal distance of the ray to the cluster. */
|
||||
distance.x = len(centroid - P_c);
|
||||
distance.y = distance.x;
|
||||
point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t);
|
||||
|
@ -284,7 +283,7 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
|
|||
if (prim_id < 0) {
|
||||
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ~prim_id);
|
||||
switch (klight->type) {
|
||||
/* Function templates only modifies cos_theta_u when in_volume_segment = true */
|
||||
/* Function templates only modifies cos_theta_u when in_volume_segment = true. */
|
||||
case LIGHT_SPOT:
|
||||
is_visible = spot_light_tree_parameters<in_volume_segment>(
|
||||
klight, centroid, P_c, cos_theta_u, distance, point_to_centroid);
|
||||
|
@ -310,7 +309,7 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
|
|||
return;
|
||||
}
|
||||
}
|
||||
else { /* mesh light */
|
||||
else { /* Mesh light. */
|
||||
is_visible = triangle_light_tree_parameters<in_volume_segment>(
|
||||
kg, kemitter, centroid, P_c, N_or_D, bcone, cos_theta_u, distance, point_to_centroid);
|
||||
}
|
||||
|
@ -346,7 +345,7 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
|
|||
max_importance = 0.0f;
|
||||
min_importance = 0.0f;
|
||||
if (knode->num_prims == 1) {
|
||||
/* At a leaf node with only one emitter */
|
||||
/* At a leaf node with only one emitter. */
|
||||
light_tree_emitter_importance<in_volume_segment>(
|
||||
kg, P, N_or_D, t, has_transmission, -knode->child_index, max_importance, min_importance);
|
||||
}
|
||||
|
@ -358,7 +357,7 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
|
|||
float cos_theta_u;
|
||||
float distance;
|
||||
if (knode->bit_trail == 1) {
|
||||
/* distant light node */
|
||||
/* Distant light node. */
|
||||
if (in_volume_segment) {
|
||||
return;
|
||||
}
|
||||
|
@ -372,7 +371,7 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
|
|||
if (in_volume_segment) {
|
||||
const float3 D = N_or_D;
|
||||
const float3 closest_point = P + dot(centroid - P, D) * D;
|
||||
/* minimal distance of the ray to the cluster */
|
||||
/* Minimal distance of the ray to the cluster. */
|
||||
distance = len(centroid - closest_point);
|
||||
point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t);
|
||||
cos_theta_u = light_tree_cos_bounding_box_angle(bbox, closest_point, point_to_centroid);
|
||||
|
@ -393,7 +392,7 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
|
|||
point_to_centroid = normalize_len(centroid - P, &distance);
|
||||
cos_theta_u = light_tree_cos_bounding_box_angle(bbox, P, point_to_centroid);
|
||||
}
|
||||
/* clamp distance to half the radius of the cluster when splitting is disabled */
|
||||
/* Clamp distance to half the radius of the cluster when splitting is disabled. */
|
||||
distance = fmaxf(0.5f * len(centroid - bbox.max), distance);
|
||||
}
|
||||
/* TODO: currently max_distance = min_distance, max_importance = min_importance for the
|
||||
|
@ -436,8 +435,8 @@ ccl_device void sample_resevoir(const int current_index,
|
|||
return;
|
||||
}
|
||||
|
||||
/* pick an emitter from a leaf node using resevoir sampling, keep two reservoirs for upper and
|
||||
* lower bounds */
|
||||
/* Pick an emitter from a leaf node using resevoir sampling, keep two reservoirs for upper and
|
||||
* lower bounds. */
|
||||
template<bool in_volume_segment>
|
||||
ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
|
||||
ccl_private float &rand,
|
||||
|
@ -452,11 +451,11 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
|
|||
float total_importance[2] = {0.0f, 0.0f};
|
||||
int selected_index = -1;
|
||||
|
||||
/* Mark emitters with zero importance. Used for resevoir when total minimum importance = 0 */
|
||||
/* Mark emitters with zero importance. Used for resevoir when total minimum importance = 0. */
|
||||
kernel_assert(knode->num_prims <= sizeof(uint) * 8);
|
||||
uint has_importance = 0;
|
||||
|
||||
const bool sample_max = (rand > 0.5f); /* sampling using the maximum importance */
|
||||
const bool sample_max = (rand > 0.5f); /* Sampling using the maximum importance. */
|
||||
rand = rand * 2.0f - float(sample_max);
|
||||
|
||||
for (int i = 0; i < knode->num_prims; i++) {
|
||||
|
@ -485,7 +484,7 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
|
|||
}
|
||||
|
||||
if (total_importance[1] == 0.0f) {
|
||||
/* uniformly sample emitters with positive maximum importance */
|
||||
/* Uniformly sample emitters with positive maximum importance. */
|
||||
if (sample_max) {
|
||||
selected_importance[1] = 1.0f;
|
||||
total_importance[1] = float(popcount(has_importance));
|
||||
|
@ -540,7 +539,7 @@ ccl_device bool get_left_probability(KernelGlobals kg,
|
|||
}
|
||||
const float total_min_importance = min_left_importance + min_right_importance;
|
||||
|
||||
/* average two probabilities of picking the left child node using lower and upper bounds */
|
||||
/* Average two probabilities of picking the left child node using lower and upper bounds. */
|
||||
const float probability_max = max_left_importance / total_max_importance;
|
||||
const float probability_min = total_min_importance > 0 ?
|
||||
min_left_importance / total_min_importance :
|
||||
|
@ -569,31 +568,31 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
|||
|
||||
const bool has_transmission = (shader_flags & SD_BSDF_HAS_TRANSMISSION);
|
||||
float pdf_leaf = 1.0f;
|
||||
float pdf_emitter_from_leaf = 1.0f;
|
||||
int selected_light = -1;
|
||||
float pdf_selection = 1.0f;
|
||||
int selected_emitter = -1;
|
||||
|
||||
int node_index = 0; /* root node */
|
||||
int node_index = 0; /* Root node. */
|
||||
|
||||
/* Traverse the light tree until a leaf node is reached. */
|
||||
while (true) {
|
||||
const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, node_index);
|
||||
|
||||
if (knode->child_index <= 0) {
|
||||
/* At a leaf node, we pick an emitter */
|
||||
selected_light = light_tree_cluster_select_emitter<in_volume_segment>(
|
||||
kg, randv, P, N_or_D, t, has_transmission, knode, &pdf_emitter_from_leaf);
|
||||
/* At a leaf node, we pick an emitter. */
|
||||
selected_emitter = light_tree_cluster_select_emitter<in_volume_segment>(
|
||||
kg, randv, P, N_or_D, t, has_transmission, knode, &pdf_selection);
|
||||
break;
|
||||
}
|
||||
|
||||
/* At an interior node, the left child is directly after the parent,
|
||||
* while the right child is stored as the child index. */
|
||||
/* At an interior node, the left child is directly after the parent, while the right child is
|
||||
* stored as the child index. */
|
||||
const int left_index = node_index + 1;
|
||||
const int right_index = knode->child_index;
|
||||
|
||||
float left_prob;
|
||||
if (!get_left_probability<in_volume_segment>(
|
||||
kg, P, N_or_D, t, has_transmission, left_index, right_index, left_prob)) {
|
||||
return false; /* both child nodes have zero importance */
|
||||
return false; /* Both child nodes have zero importance. */
|
||||
}
|
||||
|
||||
float discard;
|
||||
|
@ -603,46 +602,14 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
|||
pdf_leaf *= (node_index == left_index) ? left_prob : (1.0f - left_prob);
|
||||
}
|
||||
|
||||
if (selected_light < 0) {
|
||||
if (selected_emitter < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Sample a point on the chosen emitter */
|
||||
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
|
||||
selected_light);
|
||||
pdf_selection *= pdf_leaf;
|
||||
|
||||
/* TODO: this is the same code as light_distribution_sample, except the index is determined
|
||||
* differently. Would it be better to refactor this into a separate function? */
|
||||
const int prim = kemitter->prim_id;
|
||||
if (prim >= 0) {
|
||||
/* Mesh light. */
|
||||
const int object = kemitter->mesh_light.object_id;
|
||||
|
||||
/* Exclude synthetic meshes from shadow catcher pass. */
|
||||
if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
|
||||
!(kernel_data_fetch(object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int mesh_shader_flag = kemitter->mesh_light.shader_flag;
|
||||
if (!triangle_light_sample<in_volume_segment>(kg, prim, object, randu, randv, time, ls, P)) {
|
||||
return false;
|
||||
}
|
||||
ls->shader |= mesh_shader_flag;
|
||||
}
|
||||
else {
|
||||
if (UNLIKELY(light_select_reached_max_bounces(kg, ~prim, bounce))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!light_sample<in_volume_segment>(kg, ~prim, randu, randv, P, path_flag, ls)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ls->pdf_selection = pdf_leaf * pdf_emitter_from_leaf;
|
||||
ls->pdf *= ls->pdf_selection;
|
||||
return (ls->pdf > 0);
|
||||
return light_sample<in_volume_segment>(
|
||||
kg, randu, randv, time, P, bounce, path_flag, selected_emitter, pdf_selection, ls);
|
||||
}
|
||||
|
||||
/* We need to be able to find the probability of selecting a given light for MIS. */
|
||||
|
@ -650,7 +617,7 @@ ccl_device float light_tree_pdf(
|
|||
KernelGlobals kg, const float3 P, const float3 N, const int path_flag, const int prim)
|
||||
{
|
||||
const bool has_transmission = (path_flag & PATH_RAY_MIS_HAD_TRANSMISSION);
|
||||
/* Target emitter info */
|
||||
/* Target emitter info. */
|
||||
const int target_emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) :
|
||||
kernel_data_fetch(light_to_tree, ~prim);
|
||||
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
|
||||
|
@ -659,11 +626,11 @@ ccl_device float light_tree_pdf(
|
|||
ccl_global const KernelLightTreeNode *kleaf = &kernel_data_fetch(light_tree_nodes, target_leaf);
|
||||
uint bit_trail = kleaf->bit_trail;
|
||||
|
||||
int node_index = 0; /* root node */
|
||||
int node_index = 0; /* Root node. */
|
||||
|
||||
float pdf = 1.0f;
|
||||
|
||||
/* Traverse the light tree until we reach the target leaf node */
|
||||
/* Traverse the light tree until we reach the target leaf node. */
|
||||
while (true) {
|
||||
const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, node_index);
|
||||
|
||||
|
@ -671,7 +638,7 @@ ccl_device float light_tree_pdf(
|
|||
break;
|
||||
}
|
||||
|
||||
/* Interior node */
|
||||
/* Interior node. */
|
||||
const int left_index = node_index + 1;
|
||||
const int right_index = knode->child_index;
|
||||
|
||||
|
|
|
@ -306,7 +306,7 @@ ccl_device_forceinline bool triangle_light_tree_parameters(
|
|||
|
||||
const int object = kemitter->mesh_light.object_id;
|
||||
float3 vertices[3];
|
||||
triangle_world_space_vertices(kg, object, kemitter->prim_id, -1.0f, vertices);
|
||||
triangle_world_space_vertices(kg, object, kemitter->prim, -1.0f, vertices);
|
||||
|
||||
bool shape_above_surface = false;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
|
|
@ -1338,13 +1338,15 @@ typedef struct KernelLight {
|
|||
} KernelLight;
|
||||
static_assert_align(KernelLight, 16);
|
||||
|
||||
using MeshLight = struct MeshLight {
|
||||
int shader_flag;
|
||||
int object_id;
|
||||
};
|
||||
|
||||
typedef struct KernelLightDistribution {
|
||||
float totarea;
|
||||
int prim;
|
||||
struct {
|
||||
int shader_flag;
|
||||
int object_id;
|
||||
} mesh_light;
|
||||
MeshLight mesh_light;
|
||||
} KernelLightDistribution;
|
||||
static_assert_align(KernelLightDistribution, 16);
|
||||
|
||||
|
@ -1393,12 +1395,9 @@ typedef struct KernelLightTreeEmitter {
|
|||
float energy;
|
||||
|
||||
/* prim_id denotes the location in the lights or triangles array. */
|
||||
int prim_id;
|
||||
struct {
|
||||
int shader_flag;
|
||||
int object_id;
|
||||
EmissionSampling emission_sampling;
|
||||
} mesh_light;
|
||||
int prim;
|
||||
MeshLight mesh_light;
|
||||
EmissionSampling emission_sampling;
|
||||
|
||||
/* Parent. */
|
||||
int parent_index;
|
||||
|
|
|
@ -386,6 +386,46 @@ void ConstantFolder::fold_mix_color(NodeMix type, bool clamp_factor, bool clamp)
|
|||
}
|
||||
}
|
||||
|
||||
void ConstantFolder::fold_mix_float(bool clamp_factor, bool clamp) const
|
||||
{
|
||||
ShaderInput *fac_in = node->input("Factor");
|
||||
ShaderInput *float1_in = node->input("A");
|
||||
ShaderInput *float2_in = node->input("B");
|
||||
|
||||
float fac = clamp_factor ? saturatef(node->get_float(fac_in->socket_type)) :
|
||||
node->get_float(fac_in->socket_type);
|
||||
bool fac_is_zero = !fac_in->link && fac == 0.0f;
|
||||
bool fac_is_one = !fac_in->link && fac == 1.0f;
|
||||
|
||||
/* remove no-op node when factor is 0.0 */
|
||||
if (fac_is_zero) {
|
||||
if (try_bypass_or_make_constant(float1_in, clamp)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove useless mix floats nodes */
|
||||
if (float1_in->link && float2_in->link) {
|
||||
if (float1_in->link == float2_in->link) {
|
||||
try_bypass_or_make_constant(float1_in, clamp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!float1_in->link && !float2_in->link) {
|
||||
float value1 = node->get_float(float1_in->socket_type);
|
||||
float value2 = node->get_float(float2_in->socket_type);
|
||||
if (value1 == value2) {
|
||||
try_bypass_or_make_constant(float1_in, clamp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* remove no-op mix float node when factor is 1.0 */
|
||||
if (fac_is_one) {
|
||||
try_bypass_or_make_constant(float2_in, clamp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantFolder::fold_math(NodeMathType type) const
|
||||
{
|
||||
ShaderInput *value1_in = node->input("Value1");
|
||||
|
|
|
@ -52,6 +52,7 @@ class ConstantFolder {
|
|||
/* Specific nodes. */
|
||||
void fold_mix(NodeMix type, bool clamp) const;
|
||||
void fold_mix_color(NodeMix type, bool clamp_factor, bool clamp) const;
|
||||
void fold_mix_float(bool clamp_factor, bool clamp) const;
|
||||
void fold_math(NodeMathType type) const;
|
||||
void fold_vector_math(NodeVectorMathType type) const;
|
||||
void fold_mapping(NodeMappingType type) const;
|
||||
|
|
|
@ -88,7 +88,7 @@ NODE_DEFINE(Film)
|
|||
{
|
||||
NodeType *type = NodeType::add("film", create);
|
||||
|
||||
SOCKET_FLOAT(exposure, "Exposure", 0.8f);
|
||||
SOCKET_FLOAT(exposure, "Exposure", 1.0f);
|
||||
SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.0f);
|
||||
|
||||
static NodeEnum filter_enum;
|
||||
|
|
|
@ -253,7 +253,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
|||
|
||||
kintegrator->use_light_tree = scene->integrator->use_light_tree;
|
||||
if (light_sampling_threshold > 0.0f) {
|
||||
kintegrator->light_inv_rr_threshold = 1.0f / light_sampling_threshold;
|
||||
kintegrator->light_inv_rr_threshold = scene->film->get_exposure() / light_sampling_threshold;
|
||||
}
|
||||
else {
|
||||
kintegrator->light_inv_rr_threshold = 0.0f;
|
||||
|
|
|
@ -616,18 +616,16 @@ void LightManager::device_update_tree(Device *,
|
|||
shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER;
|
||||
}
|
||||
|
||||
light_tree_emitters[emitter_index].prim_id = prim.prim_id + mesh->prim_offset;
|
||||
light_tree_emitters[emitter_index].prim = prim.prim_id + mesh->prim_offset;
|
||||
light_tree_emitters[emitter_index].mesh_light.shader_flag = shader_flag;
|
||||
light_tree_emitters[emitter_index].mesh_light.emission_sampling =
|
||||
shader->emission_sampling;
|
||||
light_tree_emitters[emitter_index].emission_sampling = shader->emission_sampling;
|
||||
triangle_array[prim.prim_id + object_lookup_offsets[prim.object_id]] = emitter_index;
|
||||
}
|
||||
else {
|
||||
light_tree_emitters[emitter_index].prim_id = prim.prim_id;
|
||||
light_tree_emitters[emitter_index].prim = prim.prim_id;
|
||||
light_tree_emitters[emitter_index].mesh_light.shader_flag = 0;
|
||||
light_tree_emitters[emitter_index].mesh_light.object_id = OBJECT_NONE;
|
||||
light_tree_emitters[emitter_index].mesh_light.emission_sampling =
|
||||
EMISSION_SAMPLING_FRONT_BACK;
|
||||
light_tree_emitters[emitter_index].emission_sampling = EMISSION_SAMPLING_FRONT_BACK;
|
||||
light_array[~prim.prim_id] = emitter_index;
|
||||
}
|
||||
|
||||
|
@ -726,7 +724,6 @@ void LightManager::device_update_background(Device *device,
|
|||
foreach (ShaderNode *node, shader->graph->nodes) {
|
||||
if (node->type == EnvironmentTextureNode::get_node_type()) {
|
||||
EnvironmentTextureNode *env = (EnvironmentTextureNode *)node;
|
||||
ImageMetaData metadata;
|
||||
if (!env->handle.empty()) {
|
||||
ImageMetaData metadata = env->handle.metadata();
|
||||
environment_res.x = max(environment_res.x, (int)metadata.width);
|
||||
|
|
|
@ -181,7 +181,9 @@ LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
|
|||
strength *= lamp->get_shader()->emission_estimate;
|
||||
}
|
||||
|
||||
energy = average(strength);
|
||||
/* Use absolute value of energy so lights with negative strength are properly
|
||||
* supported in the light tree. */
|
||||
energy = fabsf(average(strength));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ void Shader::estimate_emission()
|
|||
}
|
||||
|
||||
ShaderInput *surf = graph->output()->input("Surface");
|
||||
emission_estimate = output_estimate_emission(surf->link, emission_is_constant);
|
||||
emission_estimate = fabs(output_estimate_emission(surf->link, emission_is_constant));
|
||||
|
||||
if (is_zero(emission_estimate)) {
|
||||
emission_sampling = EMISSION_SAMPLING_NONE;
|
||||
|
|
|
@ -5132,6 +5132,9 @@ void MixFloatNode::constant_fold(const ConstantFolder &folder)
|
|||
}
|
||||
folder.make_constant(a * (1 - fac) + b * fac);
|
||||
}
|
||||
else {
|
||||
folder.fold_mix_float(use_clamp, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mix Vector */
|
||||
|
@ -5185,6 +5188,9 @@ void MixVectorNode::constant_fold(const ConstantFolder &folder)
|
|||
}
|
||||
folder.make_constant(a * (one_float3() - fac) + b * fac);
|
||||
}
|
||||
else {
|
||||
folder.fold_mix_color(NODE_MIX_BLEND, use_clamp, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mix Vector Non Uniform */
|
||||
|
|
|
@ -167,7 +167,7 @@ add_library(bli_lib
|
|||
"../../../source/blender/blenlib/intern/rct.c"
|
||||
"../../../source/blender/blenlib/intern/string.c"
|
||||
"../../../source/blender/blenlib/intern/string_utf8.c"
|
||||
"../../../source/blender/blenlib/intern/listbase.c"
|
||||
"../../../source/blender/blenlib/intern/listbase.cc"
|
||||
"../../../source/blender/blenlib/intern/math_color.c"
|
||||
"../../../source/blender/blenlib/intern/math_geom.c"
|
||||
"../../../source/blender/blenlib/intern/math_matrix.c"
|
||||
|
|
|
@ -94,6 +94,16 @@ _namespace = globals()
|
|||
_modules_loaded = [_namespace[name] for name in _modules]
|
||||
del _namespace
|
||||
|
||||
def _addon_support_items():
|
||||
"""Return the addon support levels suitable for this Blender build."""
|
||||
|
||||
items = [
|
||||
('OFFICIAL', "Official", "Officially supported"),
|
||||
('COMMUNITY', "Community", "Maintained by community developers"),
|
||||
]
|
||||
if bpy.app.version_cycle == 'alpha':
|
||||
items.append(('TESTING', "Testing", "Newly contributed scripts (excluded from release builds)"))
|
||||
return items
|
||||
|
||||
def register():
|
||||
from bpy.utils import register_class
|
||||
|
@ -141,11 +151,7 @@ def register():
|
|||
)
|
||||
|
||||
WindowManager.addon_support = EnumProperty(
|
||||
items=[
|
||||
('OFFICIAL', "Official", "Officially supported"),
|
||||
('COMMUNITY', "Community", "Maintained by community developers"),
|
||||
('TESTING', "Testing", "Newly contributed scripts (excluded from release builds)")
|
||||
],
|
||||
items=_addon_support_items(),
|
||||
name="Support",
|
||||
description="Display support level",
|
||||
default={'OFFICIAL', 'COMMUNITY'},
|
||||
|
|
|
@ -32,8 +32,10 @@ class MotionPathButtonsPanel:
|
|||
col.prop(mps, "frame_step", text="Step")
|
||||
elif mps.type == 'RANGE':
|
||||
col = layout.column(align=True)
|
||||
col.prop(mps, "frame_start", text="Frame Range Start")
|
||||
col.prop(mps, "frame_end", text="End")
|
||||
start_end_group = col.column(align=True)
|
||||
start_end_group.active = mps.range == 'MANUAL'
|
||||
start_end_group.prop(mps, "frame_start", text="Frame Range Start")
|
||||
start_end_group.prop(mps, "frame_end", text="End")
|
||||
col.prop(mps, "frame_step", text="Step")
|
||||
|
||||
# Calculation Range
|
||||
|
|
|
@ -46,10 +46,13 @@ blender_add_lib(bf_asset_system "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
|||
|
||||
if(WITH_GTESTS)
|
||||
set(TEST_SRC
|
||||
tests/asset_catalog_test.cc
|
||||
tests/asset_catalog_path_test.cc
|
||||
tests/asset_catalog_test.cc
|
||||
tests/asset_catalog_tree_test.cc
|
||||
tests/asset_library_service_test.cc
|
||||
tests/asset_library_test.cc
|
||||
|
||||
tests/asset_library_test_common.hh
|
||||
)
|
||||
set(TEST_LIB
|
||||
bf_asset_system
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "asset_library_test_common.hh"
|
||||
|
||||
namespace blender::asset_system::tests {
|
||||
|
||||
/* UUIDs from lib/tests/asset_library/blender_assets.cats.txt */
|
||||
|
@ -76,130 +78,8 @@ class TestableAssetCatalogService : public AssetCatalogService {
|
|||
}
|
||||
};
|
||||
|
||||
class AssetCatalogTest : public testing::Test {
|
||||
class AssetCatalogTest : public AssetLibraryTestBase {
|
||||
protected:
|
||||
CatalogFilePath asset_library_root_;
|
||||
CatalogFilePath temp_library_path_;
|
||||
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
testing::Test::SetUpTestSuite();
|
||||
CLG_init();
|
||||
}
|
||||
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
CLG_exit();
|
||||
testing::Test::TearDownTestSuite();
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
|
||||
if (test_files_dir.empty()) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
asset_library_root_ = test_files_dir + SEP_STR + "asset_library";
|
||||
temp_library_path_ = "";
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
if (!temp_library_path_.empty()) {
|
||||
BLI_delete(temp_library_path_.c_str(), true, true);
|
||||
temp_library_path_ = "";
|
||||
}
|
||||
}
|
||||
|
||||
/* Register a temporary path, which will be removed at the end of the test.
|
||||
* The returned path ends in a slash. */
|
||||
CatalogFilePath use_temp_path()
|
||||
{
|
||||
BKE_tempdir_init("");
|
||||
const CatalogFilePath tempdir = BKE_tempdir_session();
|
||||
temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR;
|
||||
return temp_library_path_;
|
||||
}
|
||||
|
||||
CatalogFilePath create_temp_path()
|
||||
{
|
||||
CatalogFilePath path = use_temp_path();
|
||||
BLI_dir_create_recursive(path.c_str());
|
||||
return path;
|
||||
}
|
||||
|
||||
void assert_expected_item(const AssetCatalogPath &expected_path,
|
||||
const AssetCatalogTreeItem &actual_item)
|
||||
{
|
||||
if (expected_path != actual_item.catalog_path().str()) {
|
||||
/* This will fail, but with a nicer error message than just calling FAIL(). */
|
||||
EXPECT_EQ(expected_path, actual_item.catalog_path());
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is the catalog name as expected? "character", "Ellie", ... */
|
||||
EXPECT_EQ(expected_path.name(), actual_item.get_name());
|
||||
|
||||
/* Does the computed number of parents match? */
|
||||
const std::string expected_path_str = expected_path.str();
|
||||
const size_t expected_parent_count = std::count(
|
||||
expected_path_str.begin(), expected_path_str.end(), AssetCatalogPath::SEPARATOR);
|
||||
EXPECT_EQ(expected_parent_count, actual_item.count_parents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively iterate over all tree items using #AssetCatalogTree::foreach_item() and check if
|
||||
* the items map exactly to \a expected_paths.
|
||||
*/
|
||||
void assert_expected_tree_items(AssetCatalogTree *tree,
|
||||
const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
tree->foreach_item([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree than expected; did not expect " << actual_item.catalog_path();
|
||||
assert_expected_item(expected_paths[i], actual_item);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over the root items of \a tree and check if the items map exactly to \a
|
||||
* expected_paths. Similar to #assert_expected_tree_items() but calls
|
||||
* #AssetCatalogTree::foreach_root_item() instead of #AssetCatalogTree::foreach_item().
|
||||
*/
|
||||
void assert_expected_tree_root_items(AssetCatalogTree *tree,
|
||||
const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
tree->foreach_root_item([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree root than expected; did not expect "
|
||||
<< actual_item.catalog_path();
|
||||
assert_expected_item(expected_paths[i], actual_item);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over the child items of \a parent_item and check if the items map exactly to \a
|
||||
* expected_paths. Similar to #assert_expected_tree_items() but calls
|
||||
* #AssetCatalogTreeItem::foreach_child() instead of #AssetCatalogTree::foreach_item().
|
||||
*/
|
||||
void assert_expected_tree_item_child_items(AssetCatalogTreeItem *parent_item,
|
||||
const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
parent_item->foreach_child([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree item than expected; did not expect "
|
||||
<< actual_item.catalog_path();
|
||||
assert_expected_item(expected_paths[i], actual_item);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
/* Used by on_blendfile_save__from_memory_into_existing_asset_lib* test functions. */
|
||||
void save_from_memory_into_existing_asset_lib(const bool should_top_level_cdf_exist)
|
||||
{
|
||||
|
@ -356,149 +236,6 @@ TEST_F(AssetCatalogTest, is_first_loaded_flag)
|
|||
<< "The first-seen definition of a catalog should be returned";
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTest, insert_item_into_tree)
|
||||
{
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
std::unique_ptr<AssetCatalog> catalog_empty_path = AssetCatalog::from_path("");
|
||||
tree.insert_item(*catalog_empty_path);
|
||||
|
||||
assert_expected_tree_items(&tree, {});
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("item");
|
||||
tree.insert_item(*catalog);
|
||||
assert_expected_tree_items(&tree, {"item"});
|
||||
|
||||
/* Insert child after parent already exists. */
|
||||
std::unique_ptr<AssetCatalog> child_catalog = AssetCatalog::from_path("item/child");
|
||||
tree.insert_item(*catalog);
|
||||
assert_expected_tree_items(&tree, {"item", "item/child"});
|
||||
|
||||
std::vector<AssetCatalogPath> expected_paths;
|
||||
|
||||
/* Test inserting multi-component sub-path. */
|
||||
std::unique_ptr<AssetCatalog> grandgrandchild_catalog = AssetCatalog::from_path(
|
||||
"item/child/grandchild/grandgrandchild");
|
||||
tree.insert_item(*catalog);
|
||||
expected_paths = {
|
||||
"item", "item/child", "item/child/grandchild", "item/child/grandchild/grandgrandchild"};
|
||||
assert_expected_tree_items(&tree, expected_paths);
|
||||
|
||||
std::unique_ptr<AssetCatalog> root_level_catalog = AssetCatalog::from_path("root level");
|
||||
tree.insert_item(*catalog);
|
||||
expected_paths = {"item",
|
||||
"item/child",
|
||||
"item/child/grandchild",
|
||||
"item/child/grandchild/grandgrandchild",
|
||||
"root level"};
|
||||
assert_expected_tree_items(&tree, expected_paths);
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("item/child");
|
||||
tree.insert_item(*catalog);
|
||||
assert_expected_tree_items(&tree, {"item", "item/child"});
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("white space");
|
||||
tree.insert_item(*catalog);
|
||||
assert_expected_tree_items(&tree, {"white space"});
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("/item/white space");
|
||||
tree.insert_item(*catalog);
|
||||
assert_expected_tree_items(&tree, {"item", "item/white space"});
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog_unicode_path = AssetCatalog::from_path("Ružena");
|
||||
tree.insert_item(*catalog_unicode_path);
|
||||
assert_expected_tree_items(&tree, {"Ružena"});
|
||||
|
||||
catalog_unicode_path = AssetCatalog::from_path("Ružena/Ružena");
|
||||
tree.insert_item(*catalog_unicode_path);
|
||||
assert_expected_tree_items(&tree, {"Ružena", "Ružena/Ružena"});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTest, load_single_file_into_tree)
|
||||
{
|
||||
AssetCatalogService service(asset_library_root_);
|
||||
service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
|
||||
|
||||
/* Contains not only paths from the CDF but also the missing parents (implicitly defined
|
||||
* catalogs). */
|
||||
std::vector<AssetCatalogPath> expected_paths{
|
||||
"character",
|
||||
"character/Ellie",
|
||||
"character/Ellie/backslashes",
|
||||
"character/Ellie/poselib",
|
||||
"character/Ellie/poselib/tailslash",
|
||||
"character/Ellie/poselib/white space",
|
||||
"character/Ružena",
|
||||
"character/Ružena/poselib",
|
||||
"character/Ružena/poselib/face",
|
||||
"character/Ružena/poselib/hand",
|
||||
"path", /* Implicit. */
|
||||
"path/without", /* Implicit. */
|
||||
"path/without/simplename", /* From CDF. */
|
||||
};
|
||||
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
assert_expected_tree_items(tree, expected_paths);
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTest, foreach_in_tree)
|
||||
{
|
||||
{
|
||||
AssetCatalogTree tree{};
|
||||
const std::vector<AssetCatalogPath> no_catalogs{};
|
||||
|
||||
assert_expected_tree_items(&tree, no_catalogs);
|
||||
assert_expected_tree_root_items(&tree, no_catalogs);
|
||||
/* Need a root item to check child items. */
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("something");
|
||||
tree.insert_item(*catalog);
|
||||
tree.foreach_root_item([&no_catalogs, this](AssetCatalogTreeItem &item) {
|
||||
assert_expected_tree_item_child_items(&item, no_catalogs);
|
||||
});
|
||||
}
|
||||
|
||||
AssetCatalogService service(asset_library_root_);
|
||||
service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
|
||||
|
||||
std::vector<AssetCatalogPath> expected_root_items{{"character", "path"}};
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
assert_expected_tree_root_items(tree, expected_root_items);
|
||||
|
||||
/* Test if the direct children of the root item are what's expected. */
|
||||
std::vector<std::vector<AssetCatalogPath>> expected_root_child_items = {
|
||||
/* Children of the "character" root item. */
|
||||
{"character/Ellie", "character/Ružena"},
|
||||
/* Children of the "path" root item. */
|
||||
{"path/without"},
|
||||
};
|
||||
int i = 0;
|
||||
tree->foreach_root_item([&expected_root_child_items, &i, this](AssetCatalogTreeItem &item) {
|
||||
assert_expected_tree_item_child_items(&item, expected_root_child_items[i]);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTest, find_catalog_by_path)
|
||||
{
|
||||
TestableAssetCatalogService service(asset_library_root_);
|
||||
|
@ -832,7 +569,7 @@ TEST_F(AssetCatalogTest, delete_catalog_leaf)
|
|||
};
|
||||
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
assert_expected_tree_items(tree, expected_paths);
|
||||
AssetCatalogTreeTestFunctions::expect_tree_items(tree, expected_paths);
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
|
||||
|
@ -886,7 +623,7 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
|
|||
};
|
||||
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
assert_expected_tree_items(tree, expected_paths);
|
||||
AssetCatalogTreeTestFunctions::expect_tree_items(tree, expected_paths);
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2020 Blender Foundation. All rights reserved. */
|
||||
|
||||
#include "AS_asset_catalog.hh"
|
||||
#include "AS_asset_catalog_tree.hh"
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
#include "BKE_preferences.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_util.h"
|
||||
|
||||
#include "DNA_asset_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "asset_library_test_common.hh"
|
||||
|
||||
namespace blender::asset_system::tests {
|
||||
|
||||
static void compare_item_with_path(const AssetCatalogPath &expected_path,
|
||||
const AssetCatalogTreeItem &actual_item)
|
||||
{
|
||||
if (expected_path != actual_item.catalog_path().str()) {
|
||||
/* This will fail, but with a nicer error message than just calling FAIL(). */
|
||||
EXPECT_EQ(expected_path, actual_item.catalog_path());
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is the catalog name as expected? "character", "Ellie", ... */
|
||||
EXPECT_EQ(expected_path.name(), actual_item.get_name());
|
||||
|
||||
/* Does the computed number of parents match? */
|
||||
const std::string expected_path_str = expected_path.str();
|
||||
const size_t expected_parent_count = std::count(
|
||||
expected_path_str.begin(), expected_path_str.end(), AssetCatalogPath::SEPARATOR);
|
||||
EXPECT_EQ(expected_parent_count, actual_item.count_parents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively iterate over all tree items using #AssetCatalogTree::foreach_item() and check if
|
||||
* the items map exactly to \a expected_paths.
|
||||
*/
|
||||
void AssetCatalogTreeTestFunctions::expect_tree_items(
|
||||
AssetCatalogTree *tree, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
tree->foreach_item([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree than expected; did not expect " << actual_item.catalog_path();
|
||||
compare_item_with_path(expected_paths[i], actual_item);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over the root items of \a tree and check if the items map exactly to \a
|
||||
* expected_paths. Similar to #assert_expected_tree_items() but calls
|
||||
* #AssetCatalogTree::foreach_root_item() instead of #AssetCatalogTree::foreach_item().
|
||||
*/
|
||||
void AssetCatalogTreeTestFunctions::expect_tree_root_items(
|
||||
AssetCatalogTree *tree, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
tree->foreach_root_item([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree root than expected; did not expect "
|
||||
<< actual_item.catalog_path();
|
||||
compare_item_with_path(expected_paths[i], actual_item);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over the child items of \a parent_item and check if the items map exactly to \a
|
||||
* expected_paths. Similar to #assert_expected_tree_items() but calls
|
||||
* #AssetCatalogTreeItem::foreach_child() instead of #AssetCatalogTree::foreach_item().
|
||||
*/
|
||||
void AssetCatalogTreeTestFunctions::expect_tree_item_child_items(
|
||||
AssetCatalogTreeItem *parent_item, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
parent_item->foreach_child([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree item than expected; did not expect "
|
||||
<< actual_item.catalog_path();
|
||||
compare_item_with_path(expected_paths[i], actual_item);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
class AssetCatalogTreeTest : public AssetLibraryTestBase, public AssetCatalogTreeTestFunctions {
|
||||
};
|
||||
|
||||
TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
||||
{
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
std::unique_ptr<AssetCatalog> catalog_empty_path = AssetCatalog::from_path("");
|
||||
tree.insert_item(*catalog_empty_path);
|
||||
|
||||
expect_tree_items(&tree, {});
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("item");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"item"});
|
||||
|
||||
/* Insert child after parent already exists. */
|
||||
std::unique_ptr<AssetCatalog> child_catalog = AssetCatalog::from_path("item/child");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"item", "item/child"});
|
||||
|
||||
std::vector<AssetCatalogPath> expected_paths;
|
||||
|
||||
/* Test inserting multi-component sub-path. */
|
||||
std::unique_ptr<AssetCatalog> grandgrandchild_catalog = AssetCatalog::from_path(
|
||||
"item/child/grandchild/grandgrandchild");
|
||||
tree.insert_item(*catalog);
|
||||
expected_paths = {
|
||||
"item", "item/child", "item/child/grandchild", "item/child/grandchild/grandgrandchild"};
|
||||
expect_tree_items(&tree, expected_paths);
|
||||
|
||||
std::unique_ptr<AssetCatalog> root_level_catalog = AssetCatalog::from_path("root level");
|
||||
tree.insert_item(*catalog);
|
||||
expected_paths = {"item",
|
||||
"item/child",
|
||||
"item/child/grandchild",
|
||||
"item/child/grandchild/grandgrandchild",
|
||||
"root level"};
|
||||
expect_tree_items(&tree, expected_paths);
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("item/child");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"item", "item/child"});
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("white space");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"white space"});
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("/item/white space");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"item", "item/white space"});
|
||||
}
|
||||
|
||||
{
|
||||
AssetCatalogTree tree;
|
||||
|
||||
std::unique_ptr<AssetCatalog> catalog_unicode_path = AssetCatalog::from_path("Ružena");
|
||||
tree.insert_item(*catalog_unicode_path);
|
||||
expect_tree_items(&tree, {"Ružena"});
|
||||
|
||||
catalog_unicode_path = AssetCatalog::from_path("Ružena/Ružena");
|
||||
tree.insert_item(*catalog_unicode_path);
|
||||
expect_tree_items(&tree, {"Ružena", "Ružena/Ružena"});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTreeTest, load_single_file_into_tree)
|
||||
{
|
||||
AssetCatalogService service(asset_library_root_);
|
||||
service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
|
||||
|
||||
/* Contains not only paths from the CDF but also the missing parents (implicitly defined
|
||||
* catalogs). */
|
||||
std::vector<AssetCatalogPath> expected_paths{
|
||||
"character",
|
||||
"character/Ellie",
|
||||
"character/Ellie/backslashes",
|
||||
"character/Ellie/poselib",
|
||||
"character/Ellie/poselib/tailslash",
|
||||
"character/Ellie/poselib/white space",
|
||||
"character/Ružena",
|
||||
"character/Ružena/poselib",
|
||||
"character/Ružena/poselib/face",
|
||||
"character/Ružena/poselib/hand",
|
||||
"path", /* Implicit. */
|
||||
"path/without", /* Implicit. */
|
||||
"path/without/simplename", /* From CDF. */
|
||||
};
|
||||
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
expect_tree_items(tree, expected_paths);
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTreeTest, foreach_in_tree)
|
||||
{
|
||||
{
|
||||
AssetCatalogTree tree{};
|
||||
const std::vector<AssetCatalogPath> no_catalogs{};
|
||||
|
||||
expect_tree_items(&tree, no_catalogs);
|
||||
expect_tree_root_items(&tree, no_catalogs);
|
||||
/* Need a root item to check child items. */
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("something");
|
||||
tree.insert_item(*catalog);
|
||||
tree.foreach_root_item([&no_catalogs](AssetCatalogTreeItem &item) {
|
||||
expect_tree_item_child_items(&item, no_catalogs);
|
||||
});
|
||||
}
|
||||
|
||||
AssetCatalogService service(asset_library_root_);
|
||||
service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
|
||||
|
||||
std::vector<AssetCatalogPath> expected_root_items{{"character", "path"}};
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
expect_tree_root_items(tree, expected_root_items);
|
||||
|
||||
/* Test if the direct children of the root item are what's expected. */
|
||||
std::vector<std::vector<AssetCatalogPath>> expected_root_child_items = {
|
||||
/* Children of the "character" root item. */
|
||||
{"character/Ellie", "character/Ružena"},
|
||||
/* Children of the "path" root item. */
|
||||
{"path/without"},
|
||||
};
|
||||
int i = 0;
|
||||
tree->foreach_root_item([&expected_root_child_items, &i](AssetCatalogTreeItem &item) {
|
||||
expect_tree_item_child_items(&item, expected_root_child_items[i]);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system::tests
|
|
@ -0,0 +1,109 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_util.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
namespace blender::asset_system {
|
||||
class AssetCatalogTree;
|
||||
class AssetCatalogTreeItem;
|
||||
class AssetCatalogPath;
|
||||
} // namespace blender::asset_system
|
||||
|
||||
namespace blender::asset_system::tests {
|
||||
|
||||
/**
|
||||
* Functionality to setup and access directories on disk within which asset library related testing
|
||||
* can be done.
|
||||
*/
|
||||
class AssetLibraryTestBase : public testing::Test {
|
||||
protected:
|
||||
std::string asset_library_root_;
|
||||
std::string temp_library_path_;
|
||||
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
testing::Test::SetUpTestSuite();
|
||||
CLG_init();
|
||||
}
|
||||
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
CLG_exit();
|
||||
testing::Test::TearDownTestSuite();
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
|
||||
if (test_files_dir.empty()) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
asset_library_root_ = test_files_dir + SEP_STR + "asset_library";
|
||||
temp_library_path_ = "";
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
if (!temp_library_path_.empty()) {
|
||||
BLI_delete(temp_library_path_.c_str(), true, true);
|
||||
temp_library_path_ = "";
|
||||
}
|
||||
}
|
||||
|
||||
/* Register a temporary path, which will be removed at the end of the test.
|
||||
* The returned path ends in a slash. */
|
||||
std::string use_temp_path()
|
||||
{
|
||||
BKE_tempdir_init("");
|
||||
const std::string tempdir = BKE_tempdir_session();
|
||||
temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR;
|
||||
return temp_library_path_;
|
||||
}
|
||||
|
||||
std::string create_temp_path()
|
||||
{
|
||||
std::string path = use_temp_path();
|
||||
BLI_dir_create_recursive(path.c_str());
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
class AssetCatalogTreeTestFunctions {
|
||||
public:
|
||||
/**
|
||||
* Recursively iterate over all tree items using #AssetCatalogTree::foreach_item() and check if
|
||||
* the items map exactly to \a expected_paths.
|
||||
*/
|
||||
static void expect_tree_items(AssetCatalogTree *tree,
|
||||
const std::vector<AssetCatalogPath> &expected_paths);
|
||||
|
||||
/**
|
||||
* Iterate over the root items of \a tree and check if the items map exactly to \a
|
||||
* expected_paths. Similar to #assert_expected_tree_items() but calls
|
||||
* #AssetCatalogTree::foreach_root_item() instead of #AssetCatalogTree::foreach_item().
|
||||
*/
|
||||
static void expect_tree_root_items(AssetCatalogTree *tree,
|
||||
const std::vector<AssetCatalogPath> &expected_paths);
|
||||
|
||||
/**
|
||||
* Iterate over the child items of \a parent_item and check if the items map exactly to \a
|
||||
* expected_paths. Similar to #assert_expected_tree_items() but calls
|
||||
* #AssetCatalogTreeItem::foreach_child() instead of #AssetCatalogTree::foreach_item().
|
||||
*/
|
||||
static void expect_tree_item_child_items(AssetCatalogTreeItem *parent_item,
|
||||
const std::vector<AssetCatalogPath> &expected_paths);
|
||||
};
|
||||
|
||||
} // namespace blender::asset_system::tests
|
|
@ -421,6 +421,11 @@ inline const bNode *bNodeTree::group_output_node() const
|
|||
return this->runtime->group_output_node;
|
||||
}
|
||||
|
||||
inline blender::Span<const bNode *> bNodeTree::group_input_nodes() const
|
||||
{
|
||||
return this->nodes_by_type("NodeGroupInput");
|
||||
}
|
||||
|
||||
inline blender::Span<const bNodeSocket *> bNodeTree::all_input_sockets() const
|
||||
{
|
||||
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
|
||||
|
|
|
@ -514,6 +514,11 @@ typedef struct SculptAttribute {
|
|||
int elem_size, elem_num;
|
||||
bool data_for_bmesh; /* Temporary data store as array outside of bmesh. */
|
||||
|
||||
/* Data is a flat array outside the CustomData system.
|
||||
* This will be true if simple_array is requested in
|
||||
* SculptAttributeParams, or the PBVH type is PBVH_GRIDS or PBVH_BMESH.
|
||||
*/
|
||||
bool simple_array;
|
||||
/* Data stored per BMesh element. */
|
||||
int bmesh_cd_offset;
|
||||
|
||||
|
|
|
@ -412,7 +412,8 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, struct Mesh *me);
|
|||
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
|
||||
const int *grid_indices,
|
||||
int totgrid,
|
||||
int gridsize);
|
||||
int gridsize,
|
||||
int display_gridsize);
|
||||
|
||||
/**
|
||||
* Multi-res level, only valid for type == #PBVH_GRIDS.
|
||||
|
|
|
@ -480,6 +480,7 @@ set(SRC
|
|||
BKE_type_conversions.hh
|
||||
BKE_undo_system.h
|
||||
BKE_unit.h
|
||||
BKE_uv_islands.hh
|
||||
BKE_vfont.h
|
||||
BKE_vfontdata.h
|
||||
BKE_viewer_path.h
|
||||
|
@ -504,6 +505,7 @@ set(SRC
|
|||
intern/multires_unsubdivide.h
|
||||
intern/ocean_intern.h
|
||||
intern/pbvh_intern.h
|
||||
intern/pbvh_uv_islands.hh
|
||||
intern/subdiv_converter.h
|
||||
intern/subdiv_inline.h
|
||||
)
|
||||
|
|
|
@ -1127,7 +1127,7 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
|
|||
|
||||
/* decide on jumping & liftoff */
|
||||
if (bpa->data.mode == eBoidMode_OnLand) {
|
||||
/* fuzziness makes boids capable of misjudgement */
|
||||
/* Fuzziness makes boids capable of misjudgment. */
|
||||
float mul = 1.0f + state->rule_fuzziness;
|
||||
|
||||
if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
|
||||
|
|
|
@ -1436,7 +1436,7 @@ void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], con
|
|||
}
|
||||
|
||||
/**
|
||||
* Find roots of cubic equation (c0 x^3 + c1 x^2 + c2 x + c3)
|
||||
* Find roots of cubic equation (c0 + c1 x + c2 x^2 + c3 x^3)
|
||||
* \return number of roots in `o`.
|
||||
*
|
||||
* \note it is up to the caller to allocate enough memory for `o`.
|
||||
|
|
|
@ -1876,7 +1876,7 @@ KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force
|
|||
const float cpos = key->ctime / 100.0f;
|
||||
|
||||
/* In case of absolute keys, there is no point in adding more than one key with the same pos.
|
||||
* Hence only set new keybloc pos to current time if none previous one already use it.
|
||||
* Hence only set new key-block pos to current time if none previous one already use it.
|
||||
* Now at least people just adding absolute keys without touching to ctime
|
||||
* won't have to systematically use retiming func (and have ordering issues, too). See T39897.
|
||||
*/
|
||||
|
|
|
@ -504,14 +504,19 @@ static int customdata_compare(
|
|||
|
||||
for (int i1 = 0; i1 < c1->totlayer; i1++) {
|
||||
l1 = c1->layers + i1;
|
||||
if (l1->anonymous_id != nullptr) {
|
||||
continue;
|
||||
}
|
||||
bool found_corresponding_layer = false;
|
||||
for (int i2 = 0; i2 < c2->totlayer; i2++) {
|
||||
l2 = c2->layers + i2;
|
||||
if (l1->type != l2->type || !STREQ(l1->name, l2->name) || l1->anonymous_id != nullptr ||
|
||||
l2->anonymous_id != nullptr) {
|
||||
if (l1->type != l2->type || !STREQ(l1->name, l2->name) || l2->anonymous_id != nullptr) {
|
||||
continue;
|
||||
}
|
||||
/* At this point `l1` and `l2` have the same name and type, so they should be compared. */
|
||||
|
||||
found_corresponding_layer = true;
|
||||
|
||||
if (StringRef(l1->name) == ".corner_edge") {
|
||||
/* TODO(Hans): This attribute wasn't tested before loops were refactored into separate
|
||||
* corner edges and corner verts arrays. Remove after updating tests. */
|
||||
|
@ -690,6 +695,11 @@ static int customdata_compare(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!found_corresponding_layer) {
|
||||
if ((1 << l1->type) & CD_MASK_PROP_ALL) {
|
||||
return MESHCMP_CDLAYERS_MISMATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1335,7 +1345,7 @@ void BKE_mesh_material_index_remove(Mesh *me, short index)
|
|||
}
|
||||
MutableVArraySpan<int> indices_span(material_indices.varray);
|
||||
for (const int i : indices_span.index_range()) {
|
||||
if (indices_span[i] > 0 && indices_span[i] > index) {
|
||||
if (indices_span[i] > 0 && indices_span[i] >= index) {
|
||||
indices_span[i]--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -426,6 +426,28 @@ void multires_flush_sculpt_updates(Object *object)
|
|||
}
|
||||
|
||||
Mesh *mesh = static_cast<Mesh *>(object->data);
|
||||
|
||||
/* Check that the multires modifier still exists.
|
||||
* Fixes crash when deleting multires modifier
|
||||
* from within sculpt mode.
|
||||
*/
|
||||
ModifierData *md;
|
||||
MultiresModifierData *mmd = nullptr;
|
||||
VirtualModifierData virtualModifierData;
|
||||
|
||||
for (md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData); md;
|
||||
md = md->next) {
|
||||
if (md->type == eModifierType_Multires) {
|
||||
if (BKE_modifier_is_enabled(nullptr, md, eModifierMode_Realtime)) {
|
||||
mmd = (MultiresModifierData *)md;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mmd) {
|
||||
return;
|
||||
}
|
||||
|
||||
multiresModifier_reshapeFromCCG(
|
||||
sculpt_session->multires.modifier->totlvl, mesh, sculpt_session->subdiv_ccg);
|
||||
|
||||
|
@ -1595,7 +1617,7 @@ int mdisp_rot_face_to_crn(
|
|||
float mindist = FLT_MAX;
|
||||
|
||||
for (i = 0; i < mpoly->totloop; i++) {
|
||||
float len = len_v3v3(nullptr, positions[corner_verts[mpoly->loopstart + i]].co);
|
||||
float len = len_v3v3(nullptr, positions[corner_verts[mpoly->loopstart + i]]);
|
||||
if (len < mindist) {
|
||||
mindist = len;
|
||||
minS = i;
|
||||
|
|
|
@ -340,7 +340,7 @@ static void determine_group_input_states(
|
|||
}
|
||||
/* Check if group inputs are required to be single values, because they are (indirectly)
|
||||
* connected to some socket that does not support fields. */
|
||||
for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) {
|
||||
for (const bNode *node : tree.group_input_nodes()) {
|
||||
for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) {
|
||||
SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()];
|
||||
if (state.requires_single) {
|
||||
|
@ -349,7 +349,7 @@ static void determine_group_input_states(
|
|||
}
|
||||
}
|
||||
/* If an input does not support fields, this should be reflected in all Group Input nodes. */
|
||||
for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) {
|
||||
for (const bNode *node : tree.group_input_nodes()) {
|
||||
for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) {
|
||||
SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()];
|
||||
const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
|
||||
|
|
|
@ -4806,9 +4806,9 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
|
|||
switch (ob->type) {
|
||||
case OB_MESH: {
|
||||
Mesh *mesh = (Mesh *)ob->data;
|
||||
MutableSpan<float3> verts = mesh->positions_for_write();
|
||||
MutableSpan<float3> positions = mesh->positions_for_write();
|
||||
BKE_keyblock_convert_to_mesh(
|
||||
key->refkey, reinterpret_cast<float(*)[3]>(verts.data()), mesh->totvert);
|
||||
key->refkey, reinterpret_cast<float(*)[3]>(positions.data()), mesh->totvert);
|
||||
break;
|
||||
}
|
||||
case OB_CURVES_LEGACY:
|
||||
|
|
|
@ -79,7 +79,7 @@ static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob,
|
|||
const SculptAttributeParams *params,
|
||||
PBVHType pbvhtype,
|
||||
bool flat_array_for_bmesh);
|
||||
void sculptsession_bmesh_add_layers(Object *ob);
|
||||
static void sculptsession_bmesh_add_layers(Object *ob);
|
||||
|
||||
static void palette_init_data(ID *id)
|
||||
{
|
||||
|
@ -2459,7 +2459,7 @@ static bool sculpt_attribute_create(SculptSession *ss,
|
|||
permanent = (out->params.permanent = false);
|
||||
}
|
||||
|
||||
simple_array = (out->params.simple_array = true);
|
||||
simple_array = true;
|
||||
}
|
||||
|
||||
BLI_assert(!(simple_array && permanent));
|
||||
|
@ -2472,6 +2472,7 @@ static bool sculpt_attribute_create(SculptSession *ss,
|
|||
out->data = MEM_calloc_arrayN(totelem, elemsize, __func__);
|
||||
|
||||
out->data_for_bmesh = ss->bm != nullptr;
|
||||
out->simple_array = true;
|
||||
out->bmesh_cd_offset = -1;
|
||||
out->layer = nullptr;
|
||||
out->elem_size = elemsize;
|
||||
|
@ -2481,6 +2482,8 @@ static bool sculpt_attribute_create(SculptSession *ss,
|
|||
return true;
|
||||
}
|
||||
|
||||
out->simple_array = false;
|
||||
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_BMESH: {
|
||||
CustomData *cdata = nullptr;
|
||||
|
@ -2516,8 +2519,6 @@ static bool sculpt_attribute_create(SculptSession *ss,
|
|||
case PBVH_FACES: {
|
||||
CustomData *cdata = nullptr;
|
||||
|
||||
out->data_for_bmesh = false;
|
||||
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
cdata = &me->vdata;
|
||||
|
@ -2539,10 +2540,10 @@ static bool sculpt_attribute_create(SculptSession *ss,
|
|||
cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
|
||||
}
|
||||
|
||||
out->data = nullptr;
|
||||
out->layer = cdata->layers + index;
|
||||
out->bmesh_cd_offset = -1;
|
||||
out->data = out->layer->data;
|
||||
out->data_for_bmesh = false;
|
||||
out->bmesh_cd_offset = -1;
|
||||
out->elem_size = CustomData_get_elem_size(out->layer);
|
||||
|
||||
break;
|
||||
|
@ -2570,31 +2571,36 @@ static bool sculpt_attr_update(Object *ob, SculptAttribute *attr)
|
|||
|
||||
bool bad = false;
|
||||
|
||||
if (attr->params.simple_array) {
|
||||
if (attr->data) {
|
||||
bad = attr->elem_num != elem_num;
|
||||
|
||||
if (bad) {
|
||||
MEM_SAFE_FREE(attr->data);
|
||||
}
|
||||
else {
|
||||
attr->data_for_bmesh = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
CustomData *cdata = sculpt_get_cdata(ob, attr->domain);
|
||||
|
||||
if (cdata) {
|
||||
int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name);
|
||||
/* Check if we are a coerced simple array and shouldn't be. */
|
||||
bad |= attr->simple_array && !attr->params.simple_array &&
|
||||
!ELEM(BKE_pbvh_type(ss->pbvh), PBVH_GRIDS, PBVH_BMESH);
|
||||
|
||||
bad |= (ss->bm != nullptr) != attr->data_for_bmesh;
|
||||
CustomData *cdata = sculpt_get_cdata(ob, attr->domain);
|
||||
if (cdata && !attr->simple_array) {
|
||||
int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name);
|
||||
|
||||
bad |= layer_index == -1;
|
||||
bad |= (ss->bm != nullptr) != attr->data_for_bmesh;
|
||||
|
||||
if (!bad) {
|
||||
if (attr->data_for_bmesh) {
|
||||
attr->bmesh_cd_offset = cdata->layers[layer_index].offset;
|
||||
}
|
||||
else {
|
||||
attr->data = cdata->layers[layer_index].data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
if (attr->simple_array) {
|
||||
MEM_SAFE_FREE(attr->data);
|
||||
}
|
||||
|
||||
sculpt_attribute_create(ss,
|
||||
ob,
|
||||
attr->domain,
|
||||
|
@ -2603,7 +2609,7 @@ static bool sculpt_attr_update(Object *ob, SculptAttribute *attr)
|
|||
attr,
|
||||
&attr->params,
|
||||
BKE_pbvh_type(ss->pbvh),
|
||||
true);
|
||||
attr->data_for_bmesh);
|
||||
}
|
||||
|
||||
return bad;
|
||||
|
@ -2729,6 +2735,8 @@ static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob,
|
|||
SculptAttribute *attr = BKE_sculpt_attribute_get(ob, domain, proptype, name);
|
||||
|
||||
if (attr) {
|
||||
sculpt_attr_update(ob, attr);
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
|
@ -2767,7 +2775,7 @@ static void sculptsession_bmesh_attr_update_internal(Object *ob)
|
|||
}
|
||||
}
|
||||
|
||||
void sculptsession_bmesh_add_layers(Object *ob)
|
||||
static void sculptsession_bmesh_add_layers(Object *ob)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptAttributeParams params = {0};
|
||||
|
@ -2874,7 +2882,7 @@ bool BKE_sculpt_attribute_destroy(Object *ob, SculptAttribute *attr)
|
|||
|
||||
Mesh *me = BKE_object_get_original_mesh(ob);
|
||||
|
||||
if (attr->params.simple_array) {
|
||||
if (attr->simple_array) {
|
||||
MEM_SAFE_FREE(attr->data);
|
||||
}
|
||||
else if (ss->bm) {
|
||||
|
|
|
@ -383,7 +383,8 @@ static void update_vb(PBVH *pbvh, PBVHNode *node, BBC *prim_bbc, int offset, int
|
|||
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
|
||||
const int *grid_indices,
|
||||
int totgrid,
|
||||
int gridsize)
|
||||
int gridsize,
|
||||
int display_gridsize)
|
||||
{
|
||||
const int gridarea = (gridsize - 1) * (gridsize - 1);
|
||||
int totquad = 0;
|
||||
|
@ -391,13 +392,18 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
|
|||
/* grid hidden layer is present, so have to check each grid for
|
||||
* visibility */
|
||||
|
||||
int depth1 = (int)(log2((double)gridsize - 1.0) + DBL_EPSILON);
|
||||
int depth2 = (int)(log2((double)display_gridsize - 1.0) + DBL_EPSILON);
|
||||
|
||||
int skip = depth2 < depth1 ? 1 << (depth1 - depth2 - 1) : 1;
|
||||
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
const BLI_bitmap *gh = grid_hidden[grid_indices[i]];
|
||||
|
||||
if (gh) {
|
||||
/* grid hidden are present, have to check each element */
|
||||
for (int y = 0; y < gridsize - 1; y++) {
|
||||
for (int x = 0; x < gridsize - 1; x++) {
|
||||
for (int y = 0; y < gridsize - skip; y += skip) {
|
||||
for (int x = 0; x < gridsize - skip; x += skip) {
|
||||
if (!paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
totquad++;
|
||||
}
|
||||
|
@ -414,8 +420,11 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
|
|||
|
||||
static void build_grid_leaf_node(PBVH *pbvh, PBVHNode *node)
|
||||
{
|
||||
int totquads = BKE_pbvh_count_grid_quads(
|
||||
pbvh->grid_hidden, node->prim_indices, node->totprim, pbvh->gridkey.grid_size);
|
||||
int totquads = BKE_pbvh_count_grid_quads(pbvh->grid_hidden,
|
||||
node->prim_indices,
|
||||
node->totprim,
|
||||
pbvh->gridkey.grid_size,
|
||||
pbvh->gridkey.grid_size);
|
||||
BKE_pbvh_node_fully_hidden_set(node, (totquads == 0));
|
||||
BKE_pbvh_node_mark_rebuild_draw(node);
|
||||
}
|
||||
|
|
|
@ -361,8 +361,10 @@ static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
|
|||
return;
|
||||
}
|
||||
|
||||
uv_islands::MeshData mesh_data(
|
||||
pbvh->looptri, pbvh->totprim, pbvh->totvert, pbvh->corner_verts, ldata_uv);
|
||||
uv_islands::MeshData mesh_data({pbvh->looptri, pbvh->totprim},
|
||||
{pbvh->corner_verts, mesh->totloop},
|
||||
pbvh->totvert,
|
||||
{ldata_uv, mesh->totloop});
|
||||
uv_islands::UVIslands islands(mesh_data);
|
||||
|
||||
uv_islands::UVIslandsMask uv_masks;
|
||||
|
@ -385,7 +387,7 @@ static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
|
|||
islands.extend_borders(uv_masks);
|
||||
update_geom_primitives(*pbvh, mesh_data);
|
||||
|
||||
UVPrimitiveLookup uv_primitive_lookup(mesh_data.looptri_len, islands);
|
||||
UVPrimitiveLookup uv_primitive_lookup(mesh_data.looptris.size(), islands);
|
||||
|
||||
EncodePixelsUserData user_data;
|
||||
user_data.pbvh = pbvh;
|
||||
|
|
|
@ -95,8 +95,8 @@ rctf MeshPrimitive::uv_bounds() const
|
|||
|
||||
static void mesh_data_init_vertices(MeshData &mesh_data)
|
||||
{
|
||||
mesh_data.vertices.reserve(mesh_data.vert_len);
|
||||
for (int64_t i = 0; i < mesh_data.vert_len; i++) {
|
||||
mesh_data.vertices.reserve(mesh_data.verts_num);
|
||||
for (int64_t i = 0; i < mesh_data.verts_num; i++) {
|
||||
MeshVertex vert;
|
||||
vert.v = i;
|
||||
mesh_data.vertices.append(vert);
|
||||
|
@ -105,9 +105,9 @@ static void mesh_data_init_vertices(MeshData &mesh_data)
|
|||
|
||||
static void mesh_data_init_primitives(MeshData &mesh_data)
|
||||
{
|
||||
mesh_data.primitives.reserve(mesh_data.looptri_len);
|
||||
for (int64_t i = 0; i < mesh_data.looptri_len; i++) {
|
||||
const MLoopTri &tri = mesh_data.looptri[i];
|
||||
mesh_data.primitives.reserve(mesh_data.looptris.size());
|
||||
for (int64_t i = 0; i < mesh_data.looptris.size(); i++) {
|
||||
const MLoopTri &tri = mesh_data.looptris[i];
|
||||
MeshPrimitive primitive;
|
||||
primitive.index = i;
|
||||
primitive.poly = tri.poly;
|
||||
|
@ -125,10 +125,10 @@ static void mesh_data_init_primitives(MeshData &mesh_data)
|
|||
|
||||
static void mesh_data_init_edges(MeshData &mesh_data)
|
||||
{
|
||||
mesh_data.edges.reserve(mesh_data.looptri_len * 2);
|
||||
EdgeHash *eh = BLI_edgehash_new_ex(__func__, mesh_data.looptri_len * 3);
|
||||
for (int64_t i = 0; i < mesh_data.looptri_len; i++) {
|
||||
const MLoopTri &tri = mesh_data.looptri[i];
|
||||
mesh_data.edges.reserve(mesh_data.looptris.size() * 2);
|
||||
EdgeHash *eh = BLI_edgehash_new_ex(__func__, mesh_data.looptris.size() * 3);
|
||||
for (int64_t i = 0; i < mesh_data.looptris.size(); i++) {
|
||||
const MLoopTri &tri = mesh_data.looptris[i];
|
||||
MeshPrimitive &primitive = mesh_data.primitives[i];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int v1 = mesh_data.corner_verts[tri.tri[j]];
|
||||
|
@ -215,16 +215,11 @@ static void mesh_data_init(MeshData &mesh_data)
|
|||
mesh_data_init_primitive_uv_island_ids(mesh_data);
|
||||
}
|
||||
|
||||
MeshData::MeshData(const MLoopTri *looptri,
|
||||
const int64_t looptri_len,
|
||||
const int64_t vert_len,
|
||||
const int *corner_verts,
|
||||
const MLoopUV *mloopuv)
|
||||
: looptri(looptri),
|
||||
looptri_len(looptri_len),
|
||||
vert_len(vert_len),
|
||||
corner_verts(corner_verts),
|
||||
mloopuv(mloopuv)
|
||||
MeshData::MeshData(const Span<MLoopTri> looptris,
|
||||
const Span<int> corner_verts,
|
||||
const int verts_num,
|
||||
const Span<MLoopUV> mloopuv)
|
||||
: looptris(looptris), verts_num(verts_num), corner_verts(corner_verts), mloopuv(mloopuv)
|
||||
{
|
||||
mesh_data_init(*this);
|
||||
}
|
||||
|
|
|
@ -92,11 +92,10 @@ struct MeshPrimitive {
|
|||
*/
|
||||
struct MeshData {
|
||||
public:
|
||||
const MLoopTri *looptri;
|
||||
const int64_t looptri_len;
|
||||
const int64_t vert_len;
|
||||
const int *corner_verts;
|
||||
const MLoopUV *mloopuv;
|
||||
const Span<MLoopTri> looptris;
|
||||
const int64_t verts_num;
|
||||
const Span<int> corner_verts;
|
||||
const Span<MLoopUV> mloopuv;
|
||||
|
||||
Vector<MeshPrimitive> primitives;
|
||||
Vector<MeshEdge> edges;
|
||||
|
@ -105,11 +104,10 @@ struct MeshData {
|
|||
int64_t uv_island_len;
|
||||
|
||||
public:
|
||||
explicit MeshData(const MLoopTri *looptri,
|
||||
const int64_t looptri_len,
|
||||
const int64_t vert_len,
|
||||
const int *corner_verts,
|
||||
const MLoopUV *mloopuv);
|
||||
explicit MeshData(const Span<MLoopTri> looptris,
|
||||
const Span<int> corner_verts,
|
||||
const int verts_num,
|
||||
const Span<MLoopUV> mloopuv);
|
||||
};
|
||||
|
||||
struct UVVertex {
|
||||
|
|
|
@ -320,12 +320,15 @@ struct VolumeGrid {
|
|||
|
||||
openvdb::io::File file(filepath);
|
||||
|
||||
/* Isolate file loading since that's potentially multithreaded and we are
|
||||
/* Isolate file loading since that's potentially multi-threaded and we are
|
||||
* holding a mutex lock. */
|
||||
blender::threading::isolate_task([&] {
|
||||
try {
|
||||
/* Disable delay loading and file copying, this has poor performance
|
||||
* on network drivers. */
|
||||
const bool delay_load = false;
|
||||
file.setCopyMaxBytes(0);
|
||||
file.open();
|
||||
file.open(delay_load);
|
||||
openvdb::GridBase::Ptr vdb_grid = file.readGrid(name());
|
||||
entry->grid->setTree(vdb_grid->baseTreePtr());
|
||||
}
|
||||
|
@ -883,8 +886,11 @@ bool BKE_volume_load(const Volume *volume, const Main *bmain)
|
|||
openvdb::GridPtrVec vdb_grids;
|
||||
|
||||
try {
|
||||
/* Disable delay loading and file copying, this has poor performance
|
||||
* on network drivers. */
|
||||
const bool delay_load = false;
|
||||
file.setCopyMaxBytes(0);
|
||||
file.open();
|
||||
file.open(delay_load);
|
||||
vdb_grids = *(file.readAllGridMetadata());
|
||||
grids.metadata = file.getMetadata();
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ set(SRC
|
|||
intern/lasso_2d.c
|
||||
intern/lazy_threading.cc
|
||||
intern/length_parameterize.cc
|
||||
intern/listbase.c
|
||||
intern/listbase.cc
|
||||
intern/math_base.c
|
||||
intern/math_base_inline.c
|
||||
intern/math_base_safe_inline.c
|
||||
|
|
|
@ -22,56 +22,56 @@
|
|||
|
||||
void BLI_movelisttolist(ListBase *dst, ListBase *src)
|
||||
{
|
||||
if (src->first == NULL) {
|
||||
if (src->first == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dst->first == NULL) {
|
||||
if (dst->first == nullptr) {
|
||||
dst->first = src->first;
|
||||
dst->last = src->last;
|
||||
}
|
||||
else {
|
||||
((Link *)dst->last)->next = src->first;
|
||||
((Link *)src->first)->prev = dst->last;
|
||||
((Link *)dst->last)->next = static_cast<Link *>(src->first);
|
||||
((Link *)src->first)->prev = static_cast<Link *>(dst->last);
|
||||
dst->last = src->last;
|
||||
}
|
||||
src->first = src->last = NULL;
|
||||
src->first = src->last = nullptr;
|
||||
}
|
||||
|
||||
void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
|
||||
{
|
||||
if (src->first == NULL) {
|
||||
if (src->first == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dst->first == NULL) {
|
||||
if (dst->first == nullptr) {
|
||||
dst->first = src->first;
|
||||
dst->last = src->last;
|
||||
}
|
||||
else {
|
||||
((Link *)src->last)->next = dst->first;
|
||||
((Link *)dst->first)->prev = src->last;
|
||||
((Link *)src->last)->next = static_cast<Link *>(dst->first);
|
||||
((Link *)dst->first)->prev = static_cast<Link *>(src->last);
|
||||
dst->first = src->first;
|
||||
}
|
||||
|
||||
src->first = src->last = NULL;
|
||||
src->first = src->last = nullptr;
|
||||
}
|
||||
|
||||
void BLI_addhead(ListBase *listbase, void *vlink)
|
||||
{
|
||||
Link *link = vlink;
|
||||
Link *link = static_cast<Link *>(vlink);
|
||||
|
||||
if (link == NULL) {
|
||||
if (link == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
link->next = listbase->first;
|
||||
link->prev = NULL;
|
||||
link->next = static_cast<Link *>(listbase->first);
|
||||
link->prev = nullptr;
|
||||
|
||||
if (listbase->first) {
|
||||
((Link *)listbase->first)->prev = link;
|
||||
}
|
||||
if (listbase->last == NULL) {
|
||||
if (listbase->last == nullptr) {
|
||||
listbase->last = link;
|
||||
}
|
||||
listbase->first = link;
|
||||
|
@ -79,19 +79,19 @@ void BLI_addhead(ListBase *listbase, void *vlink)
|
|||
|
||||
void BLI_addtail(ListBase *listbase, void *vlink)
|
||||
{
|
||||
Link *link = vlink;
|
||||
Link *link = static_cast<Link *>(vlink);
|
||||
|
||||
if (link == NULL) {
|
||||
if (link == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
link->next = NULL;
|
||||
link->prev = listbase->last;
|
||||
link->next = nullptr;
|
||||
link->prev = static_cast<Link *>(listbase->last);
|
||||
|
||||
if (listbase->last) {
|
||||
((Link *)listbase->last)->next = link;
|
||||
}
|
||||
if (listbase->first == NULL) {
|
||||
if (listbase->first == nullptr) {
|
||||
listbase->first = link;
|
||||
}
|
||||
listbase->last = link;
|
||||
|
@ -99,9 +99,9 @@ void BLI_addtail(ListBase *listbase, void *vlink)
|
|||
|
||||
void BLI_remlink(ListBase *listbase, void *vlink)
|
||||
{
|
||||
Link *link = vlink;
|
||||
Link *link = static_cast<Link *>(vlink);
|
||||
|
||||
if (link == NULL) {
|
||||
if (link == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -132,8 +132,8 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink)
|
|||
|
||||
void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
|
||||
{
|
||||
Link *linka = vlinka;
|
||||
Link *linkb = vlinkb;
|
||||
Link *linka = static_cast<Link *>(vlinka);
|
||||
Link *linkb = static_cast<Link *>(vlinkb);
|
||||
|
||||
if (!linka || !linkb) {
|
||||
return;
|
||||
|
@ -185,15 +185,15 @@ void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
|
|||
|
||||
void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vlinka, void *vlinkb)
|
||||
{
|
||||
Link *linka = vlinka;
|
||||
Link *linkb = vlinkb;
|
||||
Link linkc = {NULL};
|
||||
Link *linka = static_cast<Link *>(vlinka);
|
||||
Link *linkb = static_cast<Link *>(vlinkb);
|
||||
Link linkc = {nullptr};
|
||||
|
||||
if (!linka || !linkb) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The reference to `linkc` assigns NULL, not a dangling pointer so it can be ignored. */
|
||||
/* The reference to `linkc` assigns nullptr, not a dangling pointer so it can be ignored. */
|
||||
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 1201 /* gcc12.1+ only */
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdangling-pointer"
|
||||
|
@ -221,7 +221,7 @@ void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vli
|
|||
void *BLI_pophead(ListBase *listbase)
|
||||
{
|
||||
Link *link;
|
||||
if ((link = listbase->first)) {
|
||||
if ((link = static_cast<Link *>(listbase->first))) {
|
||||
BLI_remlink(listbase, link);
|
||||
}
|
||||
return link;
|
||||
|
@ -230,7 +230,7 @@ void *BLI_pophead(ListBase *listbase)
|
|||
void *BLI_poptail(ListBase *listbase)
|
||||
{
|
||||
Link *link;
|
||||
if ((link = listbase->last)) {
|
||||
if ((link = static_cast<Link *>(listbase->last))) {
|
||||
BLI_remlink(listbase, link);
|
||||
}
|
||||
return link;
|
||||
|
@ -238,9 +238,9 @@ void *BLI_poptail(ListBase *listbase)
|
|||
|
||||
void BLI_freelinkN(ListBase *listbase, void *vlink)
|
||||
{
|
||||
Link *link = vlink;
|
||||
Link *link = static_cast<Link *>(vlink);
|
||||
|
||||
if (link == NULL) {
|
||||
if (link == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ void BLI_freelinkN(ListBase *listbase, void *vlink)
|
|||
*/
|
||||
static void listbase_double_from_single(Link *iter, ListBase *listbase)
|
||||
{
|
||||
Link *prev = NULL;
|
||||
Link *prev = nullptr;
|
||||
listbase->first = iter;
|
||||
do {
|
||||
iter->prev = prev;
|
||||
|
@ -281,7 +281,7 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
|
|||
void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
|
||||
{
|
||||
if (listbase->first != listbase->last) {
|
||||
Link *head = listbase->first;
|
||||
Link *head = static_cast<Link *>(listbase->first);
|
||||
head = listbase_sort_fn(head, cmp);
|
||||
listbase_double_from_single(head, listbase);
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ void BLI_listbase_sort_r(ListBase *listbase,
|
|||
void *thunk)
|
||||
{
|
||||
if (listbase->first != listbase->last) {
|
||||
Link *head = listbase->first;
|
||||
Link *head = static_cast<Link *>(listbase->first);
|
||||
head = listbase_sort_fn_r(head, cmp, thunk);
|
||||
listbase_double_from_single(head, listbase);
|
||||
}
|
||||
|
@ -300,25 +300,25 @@ void BLI_listbase_sort_r(ListBase *listbase,
|
|||
|
||||
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
|
||||
{
|
||||
Link *prevlink = vprevlink;
|
||||
Link *newlink = vnewlink;
|
||||
Link *prevlink = static_cast<Link *>(vprevlink);
|
||||
Link *newlink = static_cast<Link *>(vnewlink);
|
||||
|
||||
/* newlink before nextlink */
|
||||
if (newlink == NULL) {
|
||||
if (newlink == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* empty list */
|
||||
if (listbase->first == NULL) {
|
||||
if (listbase->first == nullptr) {
|
||||
listbase->first = newlink;
|
||||
listbase->last = newlink;
|
||||
return;
|
||||
}
|
||||
|
||||
/* insert at head of list */
|
||||
if (prevlink == NULL) {
|
||||
newlink->prev = NULL;
|
||||
newlink->next = listbase->first;
|
||||
if (prevlink == nullptr) {
|
||||
newlink->prev = nullptr;
|
||||
newlink->next = static_cast<Link *>(listbase->first);
|
||||
newlink->next->prev = newlink;
|
||||
listbase->first = newlink;
|
||||
return;
|
||||
|
@ -339,25 +339,25 @@ void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
|
|||
|
||||
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
|
||||
{
|
||||
Link *nextlink = vnextlink;
|
||||
Link *newlink = vnewlink;
|
||||
Link *nextlink = static_cast<Link *>(vnextlink);
|
||||
Link *newlink = static_cast<Link *>(vnewlink);
|
||||
|
||||
/* newlink before nextlink */
|
||||
if (newlink == NULL) {
|
||||
if (newlink == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* empty list */
|
||||
if (listbase->first == NULL) {
|
||||
if (listbase->first == nullptr) {
|
||||
listbase->first = newlink;
|
||||
listbase->last = newlink;
|
||||
return;
|
||||
}
|
||||
|
||||
/* insert at end of list */
|
||||
if (nextlink == NULL) {
|
||||
newlink->prev = listbase->last;
|
||||
newlink->next = NULL;
|
||||
if (nextlink == nullptr) {
|
||||
newlink->prev = static_cast<Link *>(listbase->last);
|
||||
newlink->next = nullptr;
|
||||
((Link *)listbase->last)->next = newlink;
|
||||
listbase->last = newlink;
|
||||
return;
|
||||
|
@ -378,14 +378,14 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
|
|||
|
||||
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
|
||||
{
|
||||
Link *l_old = vreplacelink;
|
||||
Link *l_new = vnewlink;
|
||||
Link *l_old = static_cast<Link *>(vreplacelink);
|
||||
Link *l_new = static_cast<Link *>(vnewlink);
|
||||
|
||||
/* update adjacent links */
|
||||
if (l_old->next != NULL) {
|
||||
if (l_old->next != nullptr) {
|
||||
l_old->next->prev = l_new;
|
||||
}
|
||||
if (l_old->prev != NULL) {
|
||||
if (l_old->prev != nullptr) {
|
||||
l_old->prev->next = l_new;
|
||||
}
|
||||
|
||||
|
@ -404,7 +404,7 @@ void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlin
|
|||
|
||||
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
|
||||
{
|
||||
Link *link = vlink;
|
||||
Link *link = static_cast<Link *>(vlink);
|
||||
Link *hook = link;
|
||||
const bool is_up = step < 0;
|
||||
|
||||
|
@ -453,7 +453,7 @@ void BLI_freelist(ListBase *listbase)
|
|||
{
|
||||
Link *link, *next;
|
||||
|
||||
link = listbase->first;
|
||||
link = static_cast<Link *>(listbase->first);
|
||||
while (link) {
|
||||
next = link->next;
|
||||
free(link);
|
||||
|
@ -467,7 +467,7 @@ void BLI_freelistN(ListBase *listbase)
|
|||
{
|
||||
Link *link, *next;
|
||||
|
||||
link = listbase->first;
|
||||
link = static_cast<Link *>(listbase->first);
|
||||
while (link) {
|
||||
next = link->next;
|
||||
MEM_freeN(link);
|
||||
|
@ -482,7 +482,8 @@ int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
|
|||
Link *link;
|
||||
int count = 0;
|
||||
|
||||
for (link = listbase->first; link && count != count_max; link = link->next) {
|
||||
for (link = static_cast<Link *>(listbase->first); link && count != count_max;
|
||||
link = link->next) {
|
||||
count++;
|
||||
}
|
||||
|
||||
|
@ -494,7 +495,7 @@ int BLI_listbase_count(const ListBase *listbase)
|
|||
Link *link;
|
||||
int count = 0;
|
||||
|
||||
for (link = listbase->first; link; link = link->next) {
|
||||
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
|
||||
count++;
|
||||
}
|
||||
|
||||
|
@ -503,11 +504,11 @@ int BLI_listbase_count(const ListBase *listbase)
|
|||
|
||||
void *BLI_findlink(const ListBase *listbase, int number)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
|
||||
if (number >= 0) {
|
||||
link = listbase->first;
|
||||
while (link != NULL && number != 0) {
|
||||
link = static_cast<Link *>(listbase->first);
|
||||
while (link != nullptr && number != 0) {
|
||||
number--;
|
||||
link = link->next;
|
||||
}
|
||||
|
@ -518,11 +519,11 @@ void *BLI_findlink(const ListBase *listbase, int number)
|
|||
|
||||
void *BLI_rfindlink(const ListBase *listbase, int number)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
|
||||
if (number >= 0) {
|
||||
link = listbase->last;
|
||||
while (link != NULL && number != 0) {
|
||||
link = static_cast<Link *>(listbase->last);
|
||||
while (link != nullptr && number != 0) {
|
||||
number--;
|
||||
link = link->prev;
|
||||
}
|
||||
|
@ -533,11 +534,11 @@ void *BLI_rfindlink(const ListBase *listbase, int number)
|
|||
|
||||
void *BLI_findlinkfrom(Link *start, int number)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
|
||||
if (number >= 0) {
|
||||
link = start;
|
||||
while (link != NULL && number != 0) {
|
||||
while (link != nullptr && number != 0) {
|
||||
number--;
|
||||
link = link->next;
|
||||
}
|
||||
|
@ -548,14 +549,14 @@ void *BLI_findlinkfrom(Link *start, int number)
|
|||
|
||||
int BLI_findindex(const ListBase *listbase, const void *vlink)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
int number = 0;
|
||||
|
||||
if (vlink == NULL) {
|
||||
if (vlink == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
link = listbase->first;
|
||||
link = static_cast<Link *>(listbase->first);
|
||||
while (link) {
|
||||
if (link == vlink) {
|
||||
return number;
|
||||
|
@ -570,14 +571,14 @@ int BLI_findindex(const ListBase *listbase, const void *vlink)
|
|||
|
||||
void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const char *id_iter;
|
||||
|
||||
if (id == NULL) {
|
||||
return NULL;
|
||||
if (id == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (link = listbase->first; link; link = link->next) {
|
||||
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
|
||||
id_iter = ((const char *)link) + offset;
|
||||
|
||||
if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
|
||||
|
@ -585,16 +586,16 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
|
||||
{
|
||||
/* Same as #BLI_findstring but find reverse. */
|
||||
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const char *id_iter;
|
||||
|
||||
for (link = listbase->last; link; link = link->prev) {
|
||||
for (link = static_cast<Link *>(listbase->last); link; link = link->prev) {
|
||||
id_iter = ((const char *)link) + offset;
|
||||
|
||||
if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
|
||||
|
@ -602,15 +603,15 @@ void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const char *id_iter;
|
||||
|
||||
for (link = listbase->first; link; link = link->next) {
|
||||
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
|
||||
/* exact copy of BLI_findstring(), except for this line */
|
||||
id_iter = *((const char **)(((const char *)link) + offset));
|
||||
|
||||
|
@ -619,16 +620,16 @@ void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int off
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
|
||||
{
|
||||
/* Same as #BLI_findstring_ptr but find reverse. */
|
||||
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const char *id_iter;
|
||||
|
||||
for (link = listbase->last; link; link = link->prev) {
|
||||
for (link = static_cast<Link *>(listbase->last); link; link = link->prev) {
|
||||
/* exact copy of BLI_rfindstring(), except for this line */
|
||||
id_iter = *((const char **)(((const char *)link) + offset));
|
||||
|
||||
|
@ -637,15 +638,15 @@ void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int of
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const void *ptr_iter;
|
||||
|
||||
for (link = listbase->first; link; link = link->next) {
|
||||
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
|
||||
/* exact copy of BLI_findstring(), except for this line */
|
||||
ptr_iter = *((const void **)(((const char *)link) + offset));
|
||||
|
||||
|
@ -654,16 +655,16 @@ void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
|
||||
{
|
||||
/* Same as #BLI_findptr but find reverse. */
|
||||
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const void *ptr_iter;
|
||||
|
||||
for (link = listbase->last; link; link = link->prev) {
|
||||
for (link = static_cast<Link *>(listbase->last); link; link = link->prev) {
|
||||
/* exact copy of BLI_rfindstring(), except for this line */
|
||||
ptr_iter = *((const void **)(((const char *)link) + offset));
|
||||
|
||||
|
@ -672,7 +673,7 @@ void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *BLI_listbase_bytes_find(const ListBase *listbase,
|
||||
|
@ -680,10 +681,10 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
|
|||
const size_t bytes_size,
|
||||
const int offset)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const void *ptr_iter;
|
||||
|
||||
for (link = listbase->first; link; link = link->next) {
|
||||
for (link = static_cast<Link *>(listbase->first); link; link = link->next) {
|
||||
ptr_iter = (const void *)(((const char *)link) + offset);
|
||||
|
||||
if (memcmp(bytes, ptr_iter, bytes_size) == 0) {
|
||||
|
@ -691,7 +692,7 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
|
||||
const void *bytes,
|
||||
|
@ -700,10 +701,10 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
|
|||
{
|
||||
/* Same as #BLI_listbase_bytes_find but find reverse. */
|
||||
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const void *ptr_iter;
|
||||
|
||||
for (link = listbase->last; link; link = link->prev) {
|
||||
for (link = static_cast<Link *>(listbase->last); link; link = link->prev) {
|
||||
ptr_iter = (const void *)(((const char *)link) + offset);
|
||||
|
||||
if (memcmp(bytes, ptr_iter, bytes_size) == 0) {
|
||||
|
@ -711,7 +712,7 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
|
|||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *BLI_listbase_string_or_index_find(const ListBase *listbase,
|
||||
|
@ -719,12 +720,13 @@ void *BLI_listbase_string_or_index_find(const ListBase *listbase,
|
|||
const size_t string_offset,
|
||||
const int index)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link_at_index = NULL;
|
||||
Link *link = nullptr;
|
||||
Link *link_at_index = nullptr;
|
||||
|
||||
int index_iter;
|
||||
for (link = listbase->first, index_iter = 0; link; link = link->next, index_iter++) {
|
||||
if (string != NULL && string[0] != '\0') {
|
||||
for (link = static_cast<Link *>(listbase->first), index_iter = 0; link;
|
||||
link = link->next, index_iter++) {
|
||||
if (string != nullptr && string[0] != '\0') {
|
||||
const char *string_iter = ((const char *)link) + string_offset;
|
||||
|
||||
if (string[0] == string_iter[0] && STREQ(string, string_iter)) {
|
||||
|
@ -740,11 +742,11 @@ void *BLI_listbase_string_or_index_find(const ListBase *listbase,
|
|||
|
||||
int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
|
||||
{
|
||||
Link *link = NULL;
|
||||
Link *link = nullptr;
|
||||
const char *id_iter;
|
||||
int i = 0;
|
||||
|
||||
link = listbase->first;
|
||||
link = static_cast<Link *>(listbase->first);
|
||||
while (link) {
|
||||
id_iter = ((const char *)link) + offset;
|
||||
|
||||
|
@ -761,17 +763,17 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
|
|||
ListBase BLI_listbase_from_link(Link *some_link)
|
||||
{
|
||||
ListBase list = {some_link, some_link};
|
||||
if (some_link == NULL) {
|
||||
if (some_link == nullptr) {
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Find the first element. */
|
||||
while (((Link *)list.first)->prev != NULL) {
|
||||
while (((Link *)list.first)->prev != nullptr) {
|
||||
list.first = ((Link *)list.first)->prev;
|
||||
}
|
||||
|
||||
/* Find the last element. */
|
||||
while (((Link *)list.last)->next != NULL) {
|
||||
while (((Link *)list.last)->next != nullptr) {
|
||||
list.last = ((Link *)list.last)->next;
|
||||
}
|
||||
|
||||
|
@ -783,11 +785,11 @@ void BLI_duplicatelist(ListBase *dst, const ListBase *src)
|
|||
struct Link *dst_link, *src_link;
|
||||
|
||||
/* in this order, to ensure it works if dst == src */
|
||||
src_link = src->first;
|
||||
dst->first = dst->last = NULL;
|
||||
src_link = static_cast<Link *>(src->first);
|
||||
dst->first = dst->last = nullptr;
|
||||
|
||||
while (src_link) {
|
||||
dst_link = MEM_dupallocN(src_link);
|
||||
dst_link = static_cast<Link *>(MEM_dupallocN(src_link));
|
||||
BLI_addtail(dst, dst_link);
|
||||
|
||||
src_link = src_link->next;
|
||||
|
@ -796,9 +798,9 @@ void BLI_duplicatelist(ListBase *dst, const ListBase *src)
|
|||
|
||||
void BLI_listbase_reverse(ListBase *lb)
|
||||
{
|
||||
struct Link *curr = lb->first;
|
||||
struct Link *prev = NULL;
|
||||
struct Link *next = NULL;
|
||||
struct Link *curr = static_cast<Link *>(lb->first);
|
||||
struct Link *prev = nullptr;
|
||||
struct Link *next = nullptr;
|
||||
while (curr) {
|
||||
next = curr->next;
|
||||
curr->next = prev;
|
||||
|
@ -808,7 +810,7 @@ void BLI_listbase_reverse(ListBase *lb)
|
|||
}
|
||||
|
||||
/* swap first/last */
|
||||
curr = lb->first;
|
||||
curr = static_cast<Link *>(lb->first);
|
||||
lb->first = lb->last;
|
||||
lb->last = curr;
|
||||
}
|
||||
|
@ -816,39 +818,39 @@ void BLI_listbase_reverse(ListBase *lb)
|
|||
void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
|
||||
{
|
||||
/* make circular */
|
||||
((Link *)lb->first)->prev = lb->last;
|
||||
((Link *)lb->last)->next = lb->first;
|
||||
((Link *)lb->first)->prev = static_cast<Link *>(lb->last);
|
||||
((Link *)lb->last)->next = static_cast<Link *>(lb->first);
|
||||
|
||||
lb->first = vlink;
|
||||
lb->last = ((Link *)vlink)->prev;
|
||||
|
||||
((Link *)lb->first)->prev = NULL;
|
||||
((Link *)lb->last)->next = NULL;
|
||||
((Link *)lb->first)->prev = nullptr;
|
||||
((Link *)lb->last)->next = nullptr;
|
||||
}
|
||||
|
||||
void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
|
||||
{
|
||||
/* make circular */
|
||||
((Link *)lb->first)->prev = lb->last;
|
||||
((Link *)lb->last)->next = lb->first;
|
||||
((Link *)lb->first)->prev = static_cast<Link *>(lb->last);
|
||||
((Link *)lb->last)->next = static_cast<Link *>(lb->first);
|
||||
|
||||
lb->first = ((Link *)vlink)->next;
|
||||
lb->last = vlink;
|
||||
|
||||
((Link *)lb->first)->prev = NULL;
|
||||
((Link *)lb->last)->next = NULL;
|
||||
((Link *)lb->first)->prev = nullptr;
|
||||
((Link *)lb->last)->next = nullptr;
|
||||
}
|
||||
|
||||
LinkData *BLI_genericNodeN(void *data)
|
||||
{
|
||||
LinkData *ld;
|
||||
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* create new link, and make it hold the given data */
|
||||
ld = MEM_callocN(sizeof(LinkData), __func__);
|
||||
ld = MEM_cnew<LinkData>(__func__);
|
||||
ld->data = data;
|
||||
|
||||
return ld;
|
|
@ -20,9 +20,9 @@ vec3 compute_chromatic_distortion_scale(float distance_squared)
|
|||
/* Compute the image coordinates after distortion by the given distortion scale computed by the
|
||||
* compute_distortion_scale function. Note that the function expects centered normalized UV
|
||||
* coordinates but outputs non-centered image coordinates. */
|
||||
vec2 compute_distorted_uv(vec2 uv, float scale)
|
||||
vec2 compute_distorted_uv(vec2 uv, float uv_scale)
|
||||
{
|
||||
return (uv * scale + 0.5) * texture_size(input_tx) - 0.5;
|
||||
return (uv * uv_scale + 0.5) * texture_size(input_tx) - 0.5;
|
||||
}
|
||||
|
||||
/* Compute the number of integration steps that should be used to approximate the distorted pixel
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
/* A shorthand for 1D textureSize with a zero LOD. */
|
||||
int texture_size(sampler1D sampler)
|
||||
int texture_size(sampler1D sampler_1d)
|
||||
{
|
||||
return textureSize(sampler, 0);
|
||||
return textureSize(sampler_1d, 0);
|
||||
}
|
||||
|
||||
/* A shorthand for 1D texelFetch with zero LOD and bounded access clamped to border. */
|
||||
vec4 texture_load(sampler1D sampler, int x)
|
||||
vec4 texture_load(sampler1D sampler_1d, int x)
|
||||
{
|
||||
const int texture_bound = texture_size(sampler) - 1;
|
||||
return texelFetch(sampler, clamp(x, 0, texture_bound), 0);
|
||||
const int texture_bound = texture_size(sampler_1d) - 1;
|
||||
return texelFetch(sampler_1d, clamp(x, 0, texture_bound), 0);
|
||||
}
|
||||
|
||||
/* A shorthand for 2D textureSize with a zero LOD. */
|
||||
ivec2 texture_size(sampler2D sampler)
|
||||
ivec2 texture_size(sampler2D sampler_2d)
|
||||
{
|
||||
return textureSize(sampler, 0);
|
||||
return textureSize(sampler_2d, 0);
|
||||
}
|
||||
|
||||
/* A shorthand for 2D texelFetch with zero LOD and bounded access clamped to border. */
|
||||
vec4 texture_load(sampler2D sampler, ivec2 texel)
|
||||
vec4 texture_load(sampler2D sampler_2d, ivec2 texel)
|
||||
{
|
||||
const ivec2 texture_bounds = texture_size(sampler) - ivec2(1);
|
||||
return texelFetch(sampler, clamp(texel, ivec2(0), texture_bounds), 0);
|
||||
const ivec2 texture_bounds = texture_size(sampler_2d) - ivec2(1);
|
||||
return texelFetch(sampler_2d, clamp(texel, ivec2(0), texture_bounds), 0);
|
||||
}
|
||||
|
||||
/* A shorthand for 2D texelFetch with zero LOD and a fallback value for out-of-bound access. */
|
||||
vec4 texture_load(sampler2D sampler, ivec2 texel, vec4 fallback)
|
||||
vec4 texture_load(sampler2D sampler_2d, ivec2 texel, vec4 fallback)
|
||||
{
|
||||
const ivec2 texture_bounds = texture_size(sampler) - ivec2(1);
|
||||
const ivec2 texture_bounds = texture_size(sampler_2d) - ivec2(1);
|
||||
if (any(lessThan(texel, ivec2(0))) || any(greaterThan(texel, texture_bounds))) {
|
||||
return fallback;
|
||||
}
|
||||
return texelFetch(sampler, texel, 0);
|
||||
return texelFetch(sampler_2d, texel, 0);
|
||||
}
|
||||
|
|
|
@ -280,6 +280,7 @@ set(SRC
|
|||
engines/image/image_buffer_cache.hh
|
||||
engines/image/image_drawing_mode.hh
|
||||
engines/image/image_engine.h
|
||||
engines/image/image_enums.hh
|
||||
engines/image/image_instance_data.hh
|
||||
engines/image/image_partial_updater.hh
|
||||
engines/image/image_private.hh
|
||||
|
@ -534,6 +535,7 @@ set(GLSL_SRC
|
|||
intern/draw_command_shared.hh
|
||||
intern/draw_common_shader_shared.h
|
||||
intern/draw_defines.h
|
||||
intern/draw_pointcloud_private.hh
|
||||
intern/draw_shader_shared.h
|
||||
|
||||
engines/gpencil/shaders/gpencil_frag.glsl
|
||||
|
|
|
@ -85,12 +85,14 @@ struct GPUBatch *DRW_pbvh_tris_get(PBVHBatches *batches,
|
|||
struct PBVHAttrReq *attrs,
|
||||
int attrs_num,
|
||||
PBVH_GPU_Args *args,
|
||||
int *r_prim_count);
|
||||
int *r_prim_count,
|
||||
bool do_coarse_grids);
|
||||
struct GPUBatch *DRW_pbvh_lines_get(struct PBVHBatches *batches,
|
||||
struct PBVHAttrReq *attrs,
|
||||
int attrs_num,
|
||||
PBVH_GPU_Args *args,
|
||||
int *r_prim_count);
|
||||
int *r_prim_count,
|
||||
bool do_coarse_grids);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -1158,7 +1158,7 @@ World *EEVEE_world_default_get(void)
|
|||
* Source is provided separately, rather than via create-info as source is manipulated
|
||||
* by `eevee_shader_material_create_info_amend`.
|
||||
*
|
||||
* We also retain the previous behaviour for ensuring library includes occur in the
|
||||
* We also retain the previous behavior for ensuring library includes occur in the
|
||||
* correct order. */
|
||||
static const char *eevee_get_vert_info(int options, char **r_src)
|
||||
{
|
||||
|
@ -1288,7 +1288,7 @@ static char *eevee_get_defines(int options)
|
|||
* CreateInfo's for EEVEE materials are declared in:
|
||||
* `eevee/shaders/infos/eevee_legacy_material_info.hh`
|
||||
*
|
||||
* This function should only contain defines which alter behaviour, but do not affect shader
|
||||
* This function should only contain defines which alter behavior, but do not affect shader
|
||||
* resources. */
|
||||
|
||||
if ((options & VAR_WORLD_BACKGROUND) != 0) {
|
||||
|
|
|
@ -21,7 +21,7 @@ GPU_SHADER_CREATE_INFO(eevee_legacy_irradiance_lib)
|
|||
GPU_SHADER_CREATE_INFO(eevee_legacy_common_utiltex_lib)
|
||||
.sampler(2, ImageType::FLOAT_2D_ARRAY, "utilTex");
|
||||
|
||||
/* Raytrace lib. */
|
||||
/* Ray-trace lib. */
|
||||
GPU_SHADER_CREATE_INFO(eevee_legacy_raytrace_lib)
|
||||
.additional_info("draw_view")
|
||||
.additional_info("eevee_legacy_common_lib")
|
||||
|
@ -33,7 +33,7 @@ GPU_SHADER_CREATE_INFO(eevee_legacy_ambient_occlusion_lib)
|
|||
.additional_info("eevee_legacy_raytrace_lib")
|
||||
.sampler(5, ImageType::FLOAT_2D, "horizonBuffer");
|
||||
|
||||
/* Lightprobe lib. */
|
||||
/* Light-probe lib. */
|
||||
GPU_SHADER_CREATE_INFO(eevee_legacy_lightprobe_lib)
|
||||
.additional_info("eevee_legacy_common_lib")
|
||||
.additional_info("eevee_legacy_common_utiltex_lib")
|
||||
|
@ -128,7 +128,7 @@ GPU_SHADER_CREATE_INFO(eevee_legacy_surface_lib_hair)
|
|||
|
||||
GPU_SHADER_CREATE_INFO(eevee_legacy_surface_lib_pointcloud)
|
||||
.define("USE_SURFACE_LIB_POINTCLOUD")
|
||||
/* Pointcloud still uses the common interface as well. */
|
||||
/* Point-cloud still uses the common interface as well. */
|
||||
.additional_info("eevee_legacy_surface_lib_common")
|
||||
.vertex_out(eevee_legacy_surface_point_cloud_iface);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
/* Voluemtric iface. */
|
||||
/* Volumetric iface. */
|
||||
GPU_SHADER_INTERFACE_INFO(legacy_volume_vert_geom_iface, "volumetric_vert_iface")
|
||||
.smooth(Type::VEC4, "vPos");
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
* dragging larger headers into the createInfo pipeline which would cause problems.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef GPU_SHADER
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
/* Hierarchical Z down-sampling. */
|
||||
#define HIZ_MIP_COUNT 8
|
||||
|
|
|
@ -26,7 +26,7 @@ shared uint bg_min_coc;
|
|||
shared uint bg_max_coc;
|
||||
shared uint bg_min_intersectable_coc;
|
||||
|
||||
const uint dof_tile_large_coc_uint = floatBitsToUint(dof_tile_large_coc);
|
||||
uint dof_tile_large_coc_uint = floatBitsToUint(dof_tile_large_coc);
|
||||
|
||||
void main()
|
||||
{
|
||||
|
|
|
@ -13,8 +13,12 @@ vec2 proj(vec4 pos)
|
|||
return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
|
||||
}
|
||||
|
||||
#define SET_INTENSITY(A, B, C, min, max) \
|
||||
(((1.0 - (float(C - B) / float(C - A))) * (max - min)) + min)
|
||||
float calc_intensity(int segment_start, int segment_current, int segment_end, float min, float max)
|
||||
{
|
||||
return ((1.0 - (float(segment_end - segment_current) / float(segment_end - segment_start))) *
|
||||
(max - min)) +
|
||||
min;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -39,10 +43,10 @@ void main()
|
|||
else {
|
||||
/* black - before frameCurrent */
|
||||
if (selected) {
|
||||
intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.25, 0.75);
|
||||
intensity = calc_intensity(frameStart, frame, frameCurrent, 0.25, 0.75);
|
||||
}
|
||||
else {
|
||||
intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.68, 0.92);
|
||||
intensity = calc_intensity(frameStart, frame, frameCurrent, 0.68, 0.92);
|
||||
}
|
||||
interp.color.rgb = mix(colorWire.rgb, blend_base, intensity);
|
||||
}
|
||||
|
@ -55,10 +59,10 @@ void main()
|
|||
else {
|
||||
/* blue - after frameCurrent */
|
||||
if (selected) {
|
||||
intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.25, 0.75);
|
||||
intensity = calc_intensity(frameCurrent, frame, frameEnd, 0.25, 0.75);
|
||||
}
|
||||
else {
|
||||
intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.68, 0.92);
|
||||
intensity = calc_intensity(frameCurrent, frame, frameEnd, 0.68, 0.92);
|
||||
}
|
||||
|
||||
interp.color.rgb = mix(colorBonePose.rgb, blend_base, intensity);
|
||||
|
|
|
@ -5,5 +5,6 @@ void main()
|
|||
{
|
||||
vData.pos = pos;
|
||||
vData.frontPosition = point_object_to_ndc(pos);
|
||||
vData.backPosition = point_object_to_ndc(pos + lightDirection * lightDistance);
|
||||
vec3 back_pos = pos + lightDirection * lightDistance;
|
||||
vData.backPosition = point_object_to_ndc(back_pos);
|
||||
}
|
||||
|
|
|
@ -217,4 +217,7 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer
|
|||
void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
|
||||
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
|
||||
RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_Z, 1, "Z", SOCK_FLOAT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1220,10 +1220,12 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd,
|
|||
GPUBatch *geom;
|
||||
|
||||
if (!scd->use_wire) {
|
||||
geom = DRW_pbvh_tris_get(batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount);
|
||||
geom = DRW_pbvh_tris_get(
|
||||
batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount, scd->fast_mode);
|
||||
}
|
||||
else {
|
||||
geom = DRW_pbvh_lines_get(batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount);
|
||||
geom = DRW_pbvh_lines_get(
|
||||
batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount, scd->fast_mode);
|
||||
}
|
||||
|
||||
short index = 0;
|
||||
|
|
|
@ -66,6 +66,22 @@ using blender::Vector;
|
|||
|
||||
using string = std::string;
|
||||
|
||||
static bool valid_pbvh_attr(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case CD_PBVH_CO_TYPE:
|
||||
case CD_PBVH_NO_TYPE:
|
||||
case CD_PBVH_FSET_TYPE:
|
||||
case CD_PBVH_MASK_TYPE:
|
||||
case CD_PROP_COLOR:
|
||||
case CD_PROP_BYTE_COLOR:
|
||||
case CD_MLOOPUV:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct PBVHVbo {
|
||||
uint64_t type;
|
||||
eAttrDomain domain;
|
||||
|
@ -99,6 +115,8 @@ struct PBVHBatch {
|
|||
string key;
|
||||
GPUBatch *tris = nullptr, *lines = nullptr;
|
||||
int tris_count = 0, lines_count = 0;
|
||||
bool is_coarse =
|
||||
false; /* Coarse multires, will use full-sized VBOs only index buffer changes. */
|
||||
|
||||
void sort_vbos(Vector<PBVHVbo> &master_vbos)
|
||||
{
|
||||
|
@ -122,6 +140,10 @@ struct PBVHBatch {
|
|||
{
|
||||
key = "";
|
||||
|
||||
if (is_coarse) {
|
||||
key += "c:";
|
||||
}
|
||||
|
||||
sort_vbos(master_vbos);
|
||||
|
||||
for (int vbo_i : vbos) {
|
||||
|
@ -157,6 +179,12 @@ struct PBVHBatches {
|
|||
|
||||
int material_index = 0;
|
||||
|
||||
/* Stuff for displaying coarse multires grids. */
|
||||
GPUIndexBuf *tri_index_coarse = nullptr;
|
||||
GPUIndexBuf *lines_index_coarse = nullptr;
|
||||
int coarse_level = 0; /* Coarse multires depth. */
|
||||
int tris_count_coarse = 0, lines_count_coarse = 0;
|
||||
|
||||
int count_faces(PBVH_GPU_Args *args)
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -178,6 +206,7 @@ struct PBVHBatches {
|
|||
count = BKE_pbvh_count_grid_quads((BLI_bitmap **)args->grid_hidden,
|
||||
args->grid_indices,
|
||||
args->totprim,
|
||||
args->ccg_key.grid_size,
|
||||
args->ccg_key.grid_size);
|
||||
|
||||
break;
|
||||
|
@ -217,9 +246,11 @@ struct PBVHBatches {
|
|||
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index_coarse);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index_coarse);
|
||||
}
|
||||
|
||||
string build_key(PBVHAttrReq *attrs, int attrs_num)
|
||||
string build_key(PBVHAttrReq *attrs, int attrs_num, bool do_coarse_grids)
|
||||
{
|
||||
string key;
|
||||
PBVHBatch batch;
|
||||
|
@ -228,6 +259,10 @@ struct PBVHBatches {
|
|||
for (int i : IndexRange(attrs_num)) {
|
||||
PBVHAttrReq *attr = attrs + i;
|
||||
|
||||
if (!valid_pbvh_attr(attr->type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PBVHVbo vbo(attr->domain, attr->type, string(attr->name));
|
||||
vbo.build_key();
|
||||
|
||||
|
@ -235,6 +270,7 @@ struct PBVHBatches {
|
|||
batch.vbos.append(i);
|
||||
}
|
||||
|
||||
batch.is_coarse = do_coarse_grids;
|
||||
batch.build_key(vbos);
|
||||
return batch.key;
|
||||
}
|
||||
|
@ -272,18 +308,21 @@ struct PBVHBatches {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool has_batch(PBVHAttrReq *attrs, int attrs_num)
|
||||
bool has_batch(PBVHAttrReq *attrs, int attrs_num, bool do_coarse_grids)
|
||||
{
|
||||
return batches.contains(build_key(attrs, attrs_num));
|
||||
return batches.contains(build_key(attrs, attrs_num, do_coarse_grids));
|
||||
}
|
||||
|
||||
PBVHBatch &ensure_batch(PBVHAttrReq *attrs, int attrs_num, PBVH_GPU_Args *args)
|
||||
PBVHBatch &ensure_batch(PBVHAttrReq *attrs,
|
||||
int attrs_num,
|
||||
PBVH_GPU_Args *args,
|
||||
bool do_coarse_grids)
|
||||
{
|
||||
if (!has_batch(attrs, attrs_num)) {
|
||||
create_batch(attrs, attrs_num, args);
|
||||
if (!has_batch(attrs, attrs_num, do_coarse_grids)) {
|
||||
create_batch(attrs, attrs_num, args, do_coarse_grids);
|
||||
}
|
||||
|
||||
return batches.lookup(build_key(attrs, attrs_num));
|
||||
return batches.lookup(build_key(attrs, attrs_num, do_coarse_grids));
|
||||
}
|
||||
|
||||
void fill_vbo_normal_faces(
|
||||
|
@ -485,9 +524,12 @@ struct PBVHBatches {
|
|||
for (int x = 0; x < gridsize; x++) {
|
||||
CCGElem *elems[4] = {
|
||||
CCG_grid_elem(&args->ccg_key, grid, x, y),
|
||||
CCG_grid_elem(&args->ccg_key, grid, x + 1, y),
|
||||
CCG_grid_elem(&args->ccg_key, grid, x + 1, y + 1),
|
||||
CCG_grid_elem(&args->ccg_key, grid, x, y + 1),
|
||||
CCG_grid_elem(&args->ccg_key, grid, min_ii(x + 1, gridsize - 1), y),
|
||||
CCG_grid_elem(&args->ccg_key,
|
||||
grid,
|
||||
min_ii(x + 1, gridsize - 1),
|
||||
min_ii(y + 1, gridsize - 1)),
|
||||
CCG_grid_elem(&args->ccg_key, grid, x, min_ii(y + 1, gridsize - 1)),
|
||||
};
|
||||
|
||||
func(x, y, grid_index, elems, 0);
|
||||
|
@ -860,10 +902,10 @@ struct PBVHBatches {
|
|||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert(0);
|
||||
printf("%s: error\n", __func__);
|
||||
printf("%s: Unsupported attribute type %d\n", __func__, type);
|
||||
BLI_assert_unreachable();
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
if (need_aliases) {
|
||||
|
@ -946,8 +988,10 @@ struct PBVHBatches {
|
|||
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(tri_index_coarse);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(lines_index_coarse);
|
||||
|
||||
tri_index = lines_index = nullptr;
|
||||
tri_index = lines_index = tri_index_coarse = lines_index_coarse = nullptr;
|
||||
faces_count = tris_count = count;
|
||||
}
|
||||
}
|
||||
|
@ -1045,7 +1089,7 @@ struct PBVHBatches {
|
|||
lines_index = GPU_indexbuf_build(&elb_lines);
|
||||
}
|
||||
|
||||
void create_index_grids(PBVH_GPU_Args *args)
|
||||
void create_index_grids(PBVH_GPU_Args *args, bool do_coarse)
|
||||
{
|
||||
int *mat_index = static_cast<int *>(
|
||||
CustomData_get_layer_named(args->pdata, CD_PROP_INT32, "material_index"));
|
||||
|
@ -1057,15 +1101,24 @@ struct PBVHBatches {
|
|||
|
||||
needs_tri_index = true;
|
||||
int gridsize = args->ccg_key.grid_size;
|
||||
int display_gridsize = gridsize;
|
||||
int totgrid = args->totprim;
|
||||
int skip = 1;
|
||||
|
||||
const int display_level = do_coarse ? coarse_level : args->ccg_key.level;
|
||||
|
||||
if (display_level < args->ccg_key.level) {
|
||||
display_gridsize = (1 << display_level) + 1;
|
||||
skip = 1 << (args->ccg_key.level - display_level - 1);
|
||||
}
|
||||
|
||||
for (int i : IndexRange(args->totprim)) {
|
||||
int grid_index = args->grid_indices[i];
|
||||
bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH;
|
||||
BLI_bitmap *gh = args->grid_hidden[grid_index];
|
||||
|
||||
for (int y = 0; y < gridsize - 1; y++) {
|
||||
for (int x = 0; x < gridsize - 1; x++) {
|
||||
for (int y = 0; y < gridsize - 1; y += skip) {
|
||||
for (int x = 0; x < gridsize - 1; x += skip) {
|
||||
if (gh && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
||||
/* Skip hidden faces by just setting smooth to true. */
|
||||
smooth = true;
|
||||
|
@ -1086,12 +1139,17 @@ struct PBVHBatches {
|
|||
|
||||
CCGKey *key = &args->ccg_key;
|
||||
|
||||
uint visible_quad_len = BKE_pbvh_count_grid_quads(
|
||||
(BLI_bitmap **)args->grid_hidden, args->grid_indices, totgrid, key->grid_size);
|
||||
uint visible_quad_len = BKE_pbvh_count_grid_quads((BLI_bitmap **)args->grid_hidden,
|
||||
args->grid_indices,
|
||||
totgrid,
|
||||
key->grid_size,
|
||||
display_gridsize);
|
||||
|
||||
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX);
|
||||
GPU_indexbuf_init(
|
||||
&elb_lines, GPU_PRIM_LINES, 2 * totgrid * gridsize * (gridsize - 1), INT_MAX);
|
||||
GPU_indexbuf_init(&elb_lines,
|
||||
GPU_PRIM_LINES,
|
||||
2 * totgrid * display_gridsize * (display_gridsize - 1),
|
||||
INT_MAX);
|
||||
|
||||
if (needs_tri_index) {
|
||||
uint offset = 0;
|
||||
|
@ -1102,17 +1160,17 @@ struct PBVHBatches {
|
|||
|
||||
BLI_bitmap *gh = args->grid_hidden[args->grid_indices[i]];
|
||||
|
||||
for (int j = 0; j < gridsize - 1; j++) {
|
||||
for (int k = 0; k < gridsize - 1; k++) {
|
||||
for (int j = 0; j < gridsize - skip; j += skip) {
|
||||
for (int k = 0; k < gridsize - skip; k += skip) {
|
||||
/* Skip hidden grid face */
|
||||
if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
|
||||
continue;
|
||||
}
|
||||
/* Indices in a Clockwise QUAD disposition. */
|
||||
v0 = offset + j * gridsize + k;
|
||||
v1 = v0 + 1;
|
||||
v2 = v1 + gridsize;
|
||||
v3 = v2 - 1;
|
||||
v1 = offset + j * gridsize + k + skip;
|
||||
v2 = offset + (j + skip) * gridsize + k + skip;
|
||||
v3 = offset + (j + skip) * gridsize + k;
|
||||
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1);
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2);
|
||||
|
@ -1120,7 +1178,7 @@ struct PBVHBatches {
|
|||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v1);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v3);
|
||||
|
||||
if (j + 2 == gridsize) {
|
||||
if (j / skip + 2 == display_gridsize) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v2, v3);
|
||||
}
|
||||
grid_visible = true;
|
||||
|
@ -1135,22 +1193,38 @@ struct PBVHBatches {
|
|||
else {
|
||||
uint offset = 0;
|
||||
const uint grid_vert_len = square_uint(gridsize - 1) * 4;
|
||||
|
||||
for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
|
||||
bool grid_visible = false;
|
||||
BLI_bitmap *gh = args->grid_hidden[args->grid_indices[i]];
|
||||
|
||||
uint v0, v1, v2, v3;
|
||||
for (int j = 0; j < gridsize - 1; j++) {
|
||||
for (int k = 0; k < gridsize - 1; k++) {
|
||||
for (int j = 0; j < gridsize - skip; j += skip) {
|
||||
for (int k = 0; k < gridsize - skip; k += skip) {
|
||||
/* Skip hidden grid face */
|
||||
if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) {
|
||||
continue;
|
||||
}
|
||||
/* VBO data are in a Clockwise QUAD disposition. */
|
||||
v0 = offset + (j * (gridsize - 1) + k) * 4;
|
||||
v1 = v0 + 1;
|
||||
v2 = v0 + 2;
|
||||
v3 = v0 + 3;
|
||||
|
||||
v0 = (j * (gridsize - 1) + k) * 4;
|
||||
|
||||
if (skip > 1) {
|
||||
v1 = (j * (gridsize - 1) + k + skip - 1) * 4;
|
||||
v2 = ((j + skip - 1) * (gridsize - 1) + k + skip - 1) * 4;
|
||||
v3 = ((j + skip - 1) * (gridsize - 1) + k) * 4;
|
||||
}
|
||||
else {
|
||||
v1 = v2 = v3 = v0;
|
||||
}
|
||||
|
||||
/* VBO data are in a Clockwise QUAD disposition. Note
|
||||
* that vertices might be in different quads if we're
|
||||
* building a coarse index buffer.
|
||||
*/
|
||||
v0 += offset;
|
||||
v1 += offset + 1;
|
||||
v2 += offset + 2;
|
||||
v3 += offset + 3;
|
||||
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1);
|
||||
GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2);
|
||||
|
@ -1158,7 +1232,7 @@ struct PBVHBatches {
|
|||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v1);
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v0, v3);
|
||||
|
||||
if (j + 2 == gridsize) {
|
||||
if ((j / skip) + 2 == display_gridsize) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v2, v3);
|
||||
}
|
||||
grid_visible = true;
|
||||
|
@ -1171,8 +1245,16 @@ struct PBVHBatches {
|
|||
}
|
||||
}
|
||||
|
||||
tri_index = GPU_indexbuf_build(&elb);
|
||||
lines_index = GPU_indexbuf_build(&elb_lines);
|
||||
if (do_coarse) {
|
||||
tri_index_coarse = GPU_indexbuf_build(&elb);
|
||||
lines_index_coarse = GPU_indexbuf_build(&elb_lines);
|
||||
tris_count_coarse = visible_quad_len;
|
||||
lines_count_coarse = totgrid * display_gridsize * (display_gridsize - 1);
|
||||
}
|
||||
else {
|
||||
tri_index = GPU_indexbuf_build(&elb);
|
||||
lines_index = GPU_indexbuf_build(&elb_lines);
|
||||
}
|
||||
}
|
||||
|
||||
void create_index(PBVH_GPU_Args *args)
|
||||
|
@ -1185,7 +1267,12 @@ struct PBVHBatches {
|
|||
create_index_bmesh(args);
|
||||
break;
|
||||
case PBVH_GRIDS:
|
||||
create_index_grids(args);
|
||||
create_index_grids(args, false);
|
||||
|
||||
if (args->ccg_key.level > coarse_level) {
|
||||
create_index_grids(args, true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1211,7 +1298,7 @@ struct PBVHBatches {
|
|||
}
|
||||
}
|
||||
|
||||
void create_batch(PBVHAttrReq *attrs, int attrs_num, PBVH_GPU_Args *args)
|
||||
void create_batch(PBVHAttrReq *attrs, int attrs_num, PBVH_GPU_Args *args, bool do_coarse_grids)
|
||||
{
|
||||
check_index_buffers(args);
|
||||
|
||||
|
@ -1220,17 +1307,23 @@ struct PBVHBatches {
|
|||
batch.tris = GPU_batch_create(GPU_PRIM_TRIS,
|
||||
nullptr,
|
||||
/* can be nullptr if buffer is empty */
|
||||
tri_index);
|
||||
batch.tris_count = tris_count;
|
||||
do_coarse_grids ? tri_index_coarse : tri_index);
|
||||
batch.tris_count = do_coarse_grids ? tris_count_coarse : tris_count;
|
||||
batch.is_coarse = do_coarse_grids;
|
||||
|
||||
if (lines_index) {
|
||||
batch.lines = GPU_batch_create(GPU_PRIM_LINES, nullptr, lines_index);
|
||||
batch.lines_count = lines_count;
|
||||
batch.lines = GPU_batch_create(
|
||||
GPU_PRIM_LINES, nullptr, do_coarse_grids ? lines_index_coarse : lines_index);
|
||||
batch.lines_count = do_coarse_grids ? lines_count_coarse : lines_count;
|
||||
}
|
||||
|
||||
for (int i : IndexRange(attrs_num)) {
|
||||
PBVHAttrReq *attr = attrs + i;
|
||||
|
||||
if (!valid_pbvh_attr(attr->type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!has_vbo(attr->domain, int(attr->type), attr->name)) {
|
||||
create_vbo(attr->domain, uint32_t(attr->type), attr->name, args);
|
||||
}
|
||||
|
@ -1276,9 +1369,12 @@ GPUBatch *DRW_pbvh_tris_get(PBVHBatches *batches,
|
|||
PBVHAttrReq *attrs,
|
||||
int attrs_num,
|
||||
PBVH_GPU_Args *args,
|
||||
int *r_prim_count)
|
||||
int *r_prim_count,
|
||||
bool do_coarse_grids)
|
||||
{
|
||||
PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args);
|
||||
do_coarse_grids &= args->pbvh_type == PBVH_GRIDS;
|
||||
|
||||
PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args, do_coarse_grids);
|
||||
|
||||
*r_prim_count = batch.tris_count;
|
||||
|
||||
|
@ -1289,9 +1385,12 @@ GPUBatch *DRW_pbvh_lines_get(PBVHBatches *batches,
|
|||
PBVHAttrReq *attrs,
|
||||
int attrs_num,
|
||||
PBVH_GPU_Args *args,
|
||||
int *r_prim_count)
|
||||
int *r_prim_count,
|
||||
bool do_coarse_grids)
|
||||
{
|
||||
PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args);
|
||||
do_coarse_grids &= args->pbvh_type == PBVH_GRIDS;
|
||||
|
||||
PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args, do_coarse_grids);
|
||||
|
||||
*r_prim_count = batch.lines_count;
|
||||
|
||||
|
|
|
@ -569,7 +569,7 @@ SamplerState PointSampler
|
|||
# define SMAAGather(tex, coord) tex.Gather(LinearSampler, coord, 0)
|
||||
# endif
|
||||
#endif
|
||||
#if defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4) || defined(GPU_METAL)
|
||||
#if defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4) || defined(GPU_METAL) || defined(GPU_VULKAN)
|
||||
# define SMAATexture2D(tex) sampler2D tex
|
||||
# define SMAATexturePass2D(tex) tex
|
||||
# define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0)
|
||||
|
@ -583,8 +583,28 @@ SamplerState PointSampler
|
|||
# define lerp(a, b, t) mix(a, b, t)
|
||||
# define saturate(a) clamp(a, 0.0, 1.0)
|
||||
# if defined(SMAA_GLSL_4)
|
||||
# define mad(a, b, c) fma(a, b, c)
|
||||
# define SMAAGather(tex, coord) textureGather(tex, coord)
|
||||
# endif
|
||||
# if defined(SMAA_GLSL_4)
|
||||
# define mad(a, b, c) fma(a, b, c)
|
||||
# elif defined(GPU_VULKAN)
|
||||
/* NOTE(Vulkan) mad macro doesn't work, define each override as work-around. */
|
||||
vec4 mad(vec4 a, vec4 b, vec4 c)
|
||||
{
|
||||
return fma(a, b, c);
|
||||
}
|
||||
vec3 mad(vec3 a, vec3 b, vec3 c)
|
||||
{
|
||||
return fma(a, b, c);
|
||||
}
|
||||
vec2 mad(vec2 a, vec2 b, vec2 c)
|
||||
{
|
||||
return fma(a, b, c);
|
||||
}
|
||||
float mad(float a, float b, float c)
|
||||
{
|
||||
return fma(a, b, c);
|
||||
}
|
||||
# else
|
||||
# define mad(a, b, c) (a * b + c)
|
||||
# endif
|
||||
|
|
|
@ -234,12 +234,28 @@ uniform mat4 ModelMatrixInverse;
|
|||
(ProjectionMatrix * (ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)))
|
||||
#define point_object_to_view(p) ((ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)).xyz)
|
||||
#define point_object_to_world(p) ((ModelMatrix * vec4(p, 1.0)).xyz)
|
||||
#define point_view_to_ndc(p) (ProjectionMatrix * vec4(p, 1.0))
|
||||
#define point_view_to_object(p) ((ModelMatrixInverse * (ViewMatrixInverse * vec4(p, 1.0))).xyz)
|
||||
#define point_view_to_world(p) ((ViewMatrixInverse * vec4(p, 1.0)).xyz)
|
||||
#define point_world_to_ndc(p) (ProjectionMatrix * (ViewMatrix * vec4(p, 1.0)))
|
||||
#define point_world_to_object(p) ((ModelMatrixInverse * vec4(p, 1.0)).xyz)
|
||||
#define point_world_to_view(p) ((ViewMatrix * vec4(p, 1.0)).xyz)
|
||||
|
||||
vec4 point_view_to_ndc(vec3 p)
|
||||
{
|
||||
return ProjectionMatrix * vec4(p, 1.0);
|
||||
}
|
||||
|
||||
vec3 point_view_to_world(vec3 p)
|
||||
{
|
||||
return (ViewMatrixInverse * vec4(p, 1.0)).xyz;
|
||||
}
|
||||
|
||||
vec4 point_world_to_ndc(vec3 p)
|
||||
{
|
||||
return ProjectionMatrix * (ViewMatrix * vec4(p, 1.0));
|
||||
}
|
||||
|
||||
vec3 point_world_to_view(vec3 p)
|
||||
{
|
||||
return (ViewMatrix * vec4(p, 1.0)).xyz;
|
||||
}
|
||||
|
||||
/* Due to some shader compiler bug, we somewhat need to access gl_VertexID
|
||||
* to make vertex shaders work. even if it's actually dead code. */
|
||||
|
|
|
@ -344,9 +344,16 @@ void animviz_motionpath_compute_range(Object *ob, Scene *scene)
|
|||
{
|
||||
bAnimVizSettings *avs = ob->mode == OB_MODE_POSE ? &ob->pose->avs : &ob->avs;
|
||||
|
||||
if (avs->path_range == MOTIONPATH_RANGE_MANUAL) {
|
||||
/* Don't touch manually-determined ranges. */
|
||||
return;
|
||||
}
|
||||
|
||||
const bool has_action = ob->adt && ob->adt->action;
|
||||
if (avs->path_range == MOTIONPATH_RANGE_SCENE || !has_action ||
|
||||
BLI_listbase_is_empty(&ob->adt->action->curves)) {
|
||||
/* Default to the scene (preview) range if there is no animation data to
|
||||
* find selected keys in. */
|
||||
avs->path_sf = PSFRA;
|
||||
avs->path_ef = PEFRA;
|
||||
return;
|
||||
|
@ -367,6 +374,7 @@ void animviz_motionpath_compute_range(Object *ob, Scene *scene)
|
|||
case MOTIONPATH_RANGE_KEYS_ALL:
|
||||
ED_keylist_all_keys_frame_range(keylist, &frame_range);
|
||||
break;
|
||||
case MOTIONPATH_RANGE_MANUAL:
|
||||
case MOTIONPATH_RANGE_SCENE:
|
||||
BLI_assert_msg(false, "This should not happen, function should have exited earlier.");
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_vector_set.hh"
|
||||
#include "ED_node.h"
|
||||
|
||||
struct SpaceNode;
|
||||
|
@ -11,6 +12,8 @@ struct bNodeTree;
|
|||
|
||||
namespace blender::ed::space_node {
|
||||
|
||||
VectorSet<bNode *> get_selected_nodes(bNodeTree &node_tree);
|
||||
|
||||
void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion);
|
||||
|
||||
/**
|
||||
|
|
|
@ -995,7 +995,7 @@ static void ui_apply_but_funcs_after(bContext *C)
|
|||
BLI_listbase_clear(&UIAfterFuncs);
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (uiAfterFunc *, afterf, &funcs) {
|
||||
uiAfterFunc after = *afterf; /* copy to avoid memleak on exit() */
|
||||
uiAfterFunc after = *afterf; /* Copy to avoid memory leak on exit(). */
|
||||
BLI_freelinkN(&funcs, afterf);
|
||||
|
||||
if (after.context) {
|
||||
|
|
|
@ -2312,7 +2312,7 @@ int UI_icon_from_rnaptr(const bContext *C, PointerRNA *ptr, int rnaicon, const b
|
|||
return rnaicon;
|
||||
}
|
||||
|
||||
/* try ID, material, texture or dynapaint slot */
|
||||
/* Try ID, material, texture or dynamic-paint slot. */
|
||||
if (RNA_struct_is_ID(ptr->type)) {
|
||||
id = ptr->owner_id;
|
||||
}
|
||||
|
|
|
@ -1345,6 +1345,11 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
|
|||
|
||||
static void sculpt_gesture_trim_begin(bContext *C, SculptGestureContext *sgcontext)
|
||||
{
|
||||
Object *object = sgcontext->vc.obact;
|
||||
SculptSession *ss = object->sculpt;
|
||||
Mesh *mesh = (Mesh *)object->data;
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
sculpt_gesture_trim_calculate_depth(sgcontext);
|
||||
sculpt_gesture_trim_geometry_generate(sgcontext);
|
||||
|
@ -1369,9 +1374,9 @@ static void sculpt_gesture_trim_end(bContext *UNUSED(C), SculptGestureContext *s
|
|||
{
|
||||
Object *object = sgcontext->vc.obact;
|
||||
SculptSession *ss = object->sculpt;
|
||||
Mesh *mesh = (Mesh *)object->data;
|
||||
|
||||
ss->face_sets = CustomData_get_layer_named(
|
||||
&((Mesh *)object->data)->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
ss->face_sets = CustomData_get_layer_named(&mesh->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
if (ss->face_sets) {
|
||||
/* Assign a new Face Set ID to the new faces created by the trim operation. */
|
||||
const int next_face_set_id = ED_sculpt_face_sets_find_next_available_id(object->data);
|
||||
|
|
|
@ -1319,6 +1319,7 @@ static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush
|
|||
*/
|
||||
static int sculpt_brush_needs_normal(const SculptSession *ss, Sculpt *sd, const Brush *brush)
|
||||
{
|
||||
const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
|
||||
return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
|
||||
(ss->cache->normal_weight > 0.0f)) ||
|
||||
SCULPT_automasking_needs_normal(ss, sd, brush) ||
|
||||
|
@ -1334,7 +1335,7 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, Sculpt *sd, const
|
|||
SCULPT_TOOL_ELASTIC_DEFORM,
|
||||
SCULPT_TOOL_THUMB) ||
|
||||
|
||||
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
|
||||
(mask_tex->brush_map_mode == MTEX_MAP_MODE_AREA)) ||
|
||||
sculpt_brush_use_topology_rake(ss, brush);
|
||||
}
|
||||
|
||||
|
@ -2861,7 +2862,7 @@ static void calc_local_y(ViewContext *vc, const float center[3], float y[3])
|
|||
mul_m4_v3(ob->world_to_object, y);
|
||||
}
|
||||
|
||||
static void calc_brush_local_mat(const Brush *brush, Object *ob, float local_mat[4][4])
|
||||
static void calc_brush_local_mat(const MTex *mtex, Object *ob, float local_mat[4][4])
|
||||
{
|
||||
const StrokeCache *cache = ob->sculpt->cache;
|
||||
float tmat[4][4];
|
||||
|
@ -2885,7 +2886,7 @@ static void calc_brush_local_mat(const Brush *brush, Object *ob, float local_mat
|
|||
/* Calculate the X axis of the local matrix. */
|
||||
cross_v3_v3v3(v, up, cache->sculpt_normal);
|
||||
/* Apply rotation (user angle, rake, etc.) to X axis. */
|
||||
angle = brush->mtex.rot - cache->special_rotation;
|
||||
angle = mtex->rot - cache->special_rotation;
|
||||
rotate_v3_v3v3fl(mat[0], v, cache->sculpt_normal, angle);
|
||||
|
||||
/* Get other axes. */
|
||||
|
@ -2932,7 +2933,9 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
|
|||
StrokeCache *cache = ob->sculpt->cache;
|
||||
|
||||
if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0) {
|
||||
calc_brush_local_mat(BKE_paint_brush(&sd->paint), ob, cache->brush_local_mat);
|
||||
const Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
|
||||
calc_brush_local_mat(mask_tex, ob, cache->brush_local_mat);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3507,7 +3510,8 @@ static void do_brush_action(Sculpt *sd,
|
|||
update_sculpt_normal(sd, ob, nodes, totnode);
|
||||
}
|
||||
|
||||
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) {
|
||||
const MTex *mask_tex = BKE_brush_mask_texture_get(brush, static_cast<eObjectMode>(ob->mode));
|
||||
if (mask_tex->brush_map_mode == MTEX_MAP_MODE_AREA) {
|
||||
update_brush_local_mat(sd, ob);
|
||||
}
|
||||
|
||||
|
@ -4042,7 +4046,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
|
|||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
MTex *mtex = &brush->mtex;
|
||||
const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
|
||||
|
||||
if (ss->multires.active && mtex->tex && mtex->tex->type == TEX_NOISE) {
|
||||
multires_stitch_grids(ob);
|
||||
|
@ -5191,12 +5195,12 @@ bool SCULPT_stroke_get_location(bContext *C,
|
|||
static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss)
|
||||
{
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
MTex *mtex = &brush->mtex;
|
||||
const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
|
||||
|
||||
/* Init mtex nodes. */
|
||||
if (mtex->tex && mtex->tex->nodetree) {
|
||||
if (mask_tex->tex && mask_tex->tex->nodetree) {
|
||||
/* Has internal flag to detect it only does it once. */
|
||||
ntreeTexBeginExecTree(mtex->tex->nodetree);
|
||||
ntreeTexBeginExecTree(mask_tex->tex->nodetree);
|
||||
}
|
||||
|
||||
if (ss->tex_pool == nullptr) {
|
||||
|
@ -5625,10 +5629,10 @@ static void sculpt_stroke_update_step(bContext *C,
|
|||
static void sculpt_brush_exit_tex(Sculpt *sd)
|
||||
{
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
MTex *mtex = &brush->mtex;
|
||||
const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
|
||||
|
||||
if (mtex->tex && mtex->tex->nodetree) {
|
||||
ntreeTexEndExecTree(mtex->tex->nodetree->runtime->execdata);
|
||||
if (mask_tex->tex && mask_tex->tex->nodetree) {
|
||||
ntreeTexEndExecTree(mask_tex->tex->nodetree->runtime->execdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -193,7 +193,8 @@ static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache)
|
|||
return expand_cache->max_vert_falloff;
|
||||
}
|
||||
|
||||
if (!expand_cache->brush->mtex.tex) {
|
||||
const MTex *mask_tex = BKE_brush_mask_texture_get(expand_cache->brush, OB_MODE_SCULPT);
|
||||
if (!mask_tex->tex) {
|
||||
return expand_cache->max_vert_falloff;
|
||||
}
|
||||
|
||||
|
@ -1882,13 +1883,14 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
|
|||
}
|
||||
case SCULPT_EXPAND_MODAL_TEXTURE_DISTORTION_INCREASE: {
|
||||
if (expand_cache->texture_distortion_strength == 0.0f) {
|
||||
if (expand_cache->brush->mtex.tex == NULL) {
|
||||
const MTex *mask_tex = BKE_brush_mask_texture_get(expand_cache->brush, OB_MODE_SCULPT);
|
||||
if (mask_tex->tex == NULL) {
|
||||
BKE_report(op->reports,
|
||||
RPT_WARNING,
|
||||
"Active brush does not contain any texture to distort the expand boundary");
|
||||
break;
|
||||
}
|
||||
if (expand_cache->brush->mtex.brush_map_mode != MTEX_MAP_MODE_3D) {
|
||||
if (mask_tex->brush_map_mode != MTEX_MAP_MODE_3D) {
|
||||
BKE_report(op->reports,
|
||||
RPT_WARNING,
|
||||
"Texture mapping not set to 3D, results may be unpredictable");
|
||||
|
@ -2052,7 +2054,6 @@ static void sculpt_expand_cache_initial_config_set(bContext *C,
|
|||
IMB_colormanagement_srgb_to_scene_linear_v3(expand_cache->fill_color, expand_cache->fill_color);
|
||||
|
||||
expand_cache->scene = CTX_data_scene(C);
|
||||
expand_cache->mtex = &expand_cache->brush->mtex;
|
||||
expand_cache->texture_distortion_strength = 0.0f;
|
||||
expand_cache->blend_mode = expand_cache->brush->blend;
|
||||
}
|
||||
|
|
|
@ -691,7 +691,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
|
|||
CustomData_get_layer(&mesh->edata, CD_CREASE));
|
||||
sculpt_face_sets_init_flood_fill(
|
||||
ob, [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
|
||||
return creases[edge] < threshold;
|
||||
return creases ? creases[edge] < threshold : true;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -708,7 +708,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
|
|||
CustomData_get_layer(&mesh->edata, CD_BWEIGHT));
|
||||
sculpt_face_sets_init_flood_fill(
|
||||
ob, [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
|
||||
return bevel_weights ? bevel_weights[edge] / 255.0f < threshold : true;
|
||||
return bevel_weights ? bevel_weights[edge] < threshold : true;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -752,7 +752,7 @@ typedef struct ExpandCache {
|
|||
/* Texture distortion data. */
|
||||
Brush *brush;
|
||||
struct Scene *scene;
|
||||
struct MTex *mtex;
|
||||
// struct MTex *mtex;
|
||||
|
||||
/* Controls how much texture distortion will be applied to the current falloff */
|
||||
float texture_distortion_strength;
|
||||
|
|
|
@ -2813,9 +2813,9 @@ static void frame_node_draw_label(TreeDrawContext &tree_draw_ctx,
|
|||
BLF_wordwrap(fontid, line_width);
|
||||
|
||||
LISTBASE_FOREACH (const TextLine *, line, &text->lines) {
|
||||
ResultBLF info;
|
||||
if (line->line[0]) {
|
||||
BLF_position(fontid, x, y, 0);
|
||||
ResultBLF info;
|
||||
BLF_draw_ex(fontid, line->line, line->len, &info);
|
||||
y -= line_spacing * info.lines;
|
||||
}
|
||||
|
@ -2890,10 +2890,8 @@ static void frame_node_draw(const bContext &C,
|
|||
static void reroute_node_draw(
|
||||
const bContext &C, ARegion ®ion, bNodeTree &ntree, bNode &node, uiBlock &block)
|
||||
{
|
||||
char showname[128]; /* 128 used below */
|
||||
const rctf &rct = node.runtime->totr;
|
||||
|
||||
/* skip if out of view */
|
||||
const rctf &rct = node.runtime->totr;
|
||||
if (rct.xmax < region.v2d.cur.xmin || rct.xmin > region.v2d.cur.xmax ||
|
||||
rct.ymax < region.v2d.cur.ymin || node.runtime->totr.ymin > region.v2d.cur.ymax) {
|
||||
UI_block_end(&C, &block);
|
||||
|
@ -2902,6 +2900,7 @@ static void reroute_node_draw(
|
|||
|
||||
if (node.label[0] != '\0') {
|
||||
/* draw title (node label) */
|
||||
char showname[128]; /* 128 used below */
|
||||
BLI_strncpy(showname, node.label, sizeof(showname));
|
||||
const short width = 512;
|
||||
const int x = BLI_rctf_cent_x(&node.runtime->totr) - (width / 2);
|
||||
|
@ -2987,7 +2986,7 @@ static void node_draw_nodetree(const bContext &C,
|
|||
continue;
|
||||
}
|
||||
|
||||
bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
|
||||
const bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
|
||||
node_draw(C, tree_draw_ctx, region, snode, ntree, *nodes[i], *blocks[i], key);
|
||||
}
|
||||
|
||||
|
@ -3017,7 +3016,7 @@ static void node_draw_nodetree(const bContext &C,
|
|||
continue;
|
||||
}
|
||||
|
||||
bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
|
||||
const bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
|
||||
node_draw(C, tree_draw_ctx, region, snode, ntree, *nodes[i], *blocks[i], key);
|
||||
}
|
||||
}
|
||||
|
@ -3025,8 +3024,6 @@ static void node_draw_nodetree(const bContext &C,
|
|||
/* Draw the breadcrumb on the top of the editor. */
|
||||
static void draw_tree_path(const bContext &C, ARegion ®ion)
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
GPU_matrix_push_projection();
|
||||
wmOrtho2_region_pixelspace(®ion);
|
||||
|
||||
|
@ -3042,7 +3039,7 @@ static void draw_tree_path(const bContext &C, ARegion ®ion)
|
|||
uiLayout *layout = UI_block_layout(
|
||||
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y, width, 1, 0, style);
|
||||
|
||||
Vector<ui::ContextPathItem> context_path = ed::space_node::context_path_for_space_node(C);
|
||||
const Vector<ui::ContextPathItem> context_path = ed::space_node::context_path_for_space_node(C);
|
||||
ui::template_breadcrumbs(*layout, context_path);
|
||||
|
||||
UI_block_layout_resolve(block, nullptr, nullptr);
|
||||
|
@ -3115,7 +3112,7 @@ static void draw_nodetree(const bContext &C,
|
|||
SpaceNode *snode = CTX_wm_space_node(&C);
|
||||
ntree.ensure_topology_cache();
|
||||
|
||||
Span<bNode *> nodes = ntree.all_nodes();
|
||||
const Span<bNode *> nodes = ntree.all_nodes();
|
||||
|
||||
Array<uiBlock *> blocks = node_uiblocks_init(C, nodes);
|
||||
|
||||
|
@ -3126,7 +3123,7 @@ static void draw_nodetree(const bContext &C,
|
|||
tree_draw_ctx.geo_tree_log->ensure_node_warnings();
|
||||
tree_draw_ctx.geo_tree_log->ensure_node_run_time();
|
||||
}
|
||||
WorkSpace *workspace = CTX_wm_workspace(&C);
|
||||
const WorkSpace *workspace = CTX_wm_workspace(&C);
|
||||
tree_draw_ctx.active_geometry_nodes_viewer = viewer_path::find_geometry_nodes_viewer(
|
||||
workspace->viewer_path, *snode);
|
||||
}
|
||||
|
|
|
@ -673,146 +673,137 @@ void ED_node_set_active(
|
|||
}
|
||||
|
||||
nodeSetActive(ntree, node);
|
||||
if (node->type == NODE_GROUP) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->type != NODE_GROUP) {
|
||||
const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
|
||||
bool do_update = false;
|
||||
const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
|
||||
bool do_update = false;
|
||||
|
||||
/* generic node group output: set node as active output */
|
||||
if (node->type == NODE_GROUP_OUTPUT) {
|
||||
/* generic node group output: set node as active output */
|
||||
if (node->type == NODE_GROUP_OUTPUT) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (node_iter->type == NODE_GROUP_OUTPUT) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
node->flag |= NODE_DO_OUTPUT;
|
||||
if (!was_output) {
|
||||
do_update = true;
|
||||
BKE_ntree_update_tag_active_output_changed(ntree);
|
||||
}
|
||||
}
|
||||
|
||||
/* tree specific activate calls */
|
||||
if (ntree->type == NTREE_SHADER) {
|
||||
if (ELEM(node->type,
|
||||
SH_NODE_OUTPUT_MATERIAL,
|
||||
SH_NODE_OUTPUT_WORLD,
|
||||
SH_NODE_OUTPUT_LIGHT,
|
||||
SH_NODE_OUTPUT_LINESTYLE)) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (node_iter->type == NODE_GROUP_OUTPUT) {
|
||||
if (node_iter->type == node->type) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
node->flag |= NODE_DO_OUTPUT;
|
||||
if (!was_output) {
|
||||
do_update = true;
|
||||
BKE_ntree_update_tag_active_output_changed(ntree);
|
||||
}
|
||||
BKE_ntree_update_tag_active_output_changed(ntree);
|
||||
}
|
||||
|
||||
/* tree specific activate calls */
|
||||
if (ntree->type == NTREE_SHADER) {
|
||||
if (ELEM(node->type,
|
||||
SH_NODE_OUTPUT_MATERIAL,
|
||||
SH_NODE_OUTPUT_WORLD,
|
||||
SH_NODE_OUTPUT_LIGHT,
|
||||
SH_NODE_OUTPUT_LINESTYLE)) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (node_iter->type == node->type) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
}
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
|
||||
node->flag |= NODE_DO_OUTPUT;
|
||||
BKE_ntree_update_tag_active_output_changed(ntree);
|
||||
}
|
||||
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
|
||||
/* If active texture changed, free glsl materials. */
|
||||
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
|
||||
if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree)) {
|
||||
GPU_material_free(&ma->gpumaterial);
|
||||
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
|
||||
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
|
||||
/* If active texture changed, free glsl materials. */
|
||||
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
|
||||
if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree)) {
|
||||
GPU_material_free(&ma->gpumaterial);
|
||||
|
||||
/* Sync to active texpaint slot, otherwise we can end up painting on a different slot
|
||||
* than we are looking at. */
|
||||
if (ma->texpaintslot) {
|
||||
if (node->id != nullptr && GS(node->id->name) == ID_IM) {
|
||||
Image *image = (Image *)node->id;
|
||||
for (int i = 0; i < ma->tot_slots; i++) {
|
||||
if (ma->texpaintslot[i].ima == image) {
|
||||
ma->paint_active_slot = i;
|
||||
}
|
||||
/* Sync to active texpaint slot, otherwise we can end up painting on a different slot
|
||||
* than we are looking at. */
|
||||
if (ma->texpaintslot) {
|
||||
if (node->id != nullptr && GS(node->id->name) == ID_IM) {
|
||||
Image *image = (Image *)node->id;
|
||||
for (int i = 0; i < ma->tot_slots; i++) {
|
||||
if (ma->texpaintslot[i].ima == image) {
|
||||
ma->paint_active_slot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (World *, wo, &bmain->worlds) {
|
||||
if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree)) {
|
||||
GPU_material_free(&wo->gpumaterial);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync to Image Editor under the following conditions:
|
||||
* - current image is not pinned
|
||||
* - current image is not a Render Result or ViewerNode (want to keep looking at these) */
|
||||
if (node->id != nullptr && GS(node->id->name) == ID_IM) {
|
||||
Image *image = (Image *)node->id;
|
||||
ED_space_image_sync(bmain, image, true);
|
||||
}
|
||||
|
||||
if (r_active_texture_changed) {
|
||||
*r_active_texture_changed = true;
|
||||
}
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_IMAGE, nullptr);
|
||||
}
|
||||
|
||||
WM_main_add_notifier(NC_MATERIAL | ND_NODES, node->id);
|
||||
LISTBASE_FOREACH (World *, wo, &bmain->worlds) {
|
||||
if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree)) {
|
||||
GPU_material_free(&wo->gpumaterial);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync to Image Editor under the following conditions:
|
||||
* - current image is not pinned
|
||||
* - current image is not a Render Result or ViewerNode (want to keep looking at these) */
|
||||
if (node->id != nullptr && GS(node->id->name) == ID_IM) {
|
||||
Image *image = (Image *)node->id;
|
||||
ED_space_image_sync(bmain, image, true);
|
||||
}
|
||||
|
||||
if (r_active_texture_changed) {
|
||||
*r_active_texture_changed = true;
|
||||
}
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_IMAGE, nullptr);
|
||||
}
|
||||
else if (ntree->type == NTREE_COMPOSIT) {
|
||||
/* make active viewer, currently only 1 supported... */
|
||||
if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
|
||||
|
||||
WM_main_add_notifier(NC_MATERIAL | ND_NODES, node->id);
|
||||
}
|
||||
else if (ntree->type == NTREE_COMPOSIT) {
|
||||
/* make active viewer, currently only 1 supported... */
|
||||
if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (ELEM(node_iter->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
node->flag |= NODE_DO_OUTPUT;
|
||||
if (was_output == 0) {
|
||||
BKE_ntree_update_tag_active_output_changed(ntree);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
|
||||
/* Adding a node doesn't link this yet. */
|
||||
node->id = (ID *)BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
|
||||
}
|
||||
else if (node->type == CMP_NODE_COMPOSITE) {
|
||||
if (was_output == 0) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (ELEM(node_iter->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
|
||||
if (node_iter->type == CMP_NODE_COMPOSITE) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
node->flag |= NODE_DO_OUTPUT;
|
||||
if (was_output == 0) {
|
||||
BKE_ntree_update_tag_active_output_changed(ntree);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
|
||||
/* Adding a node doesn't link this yet. */
|
||||
node->id = (ID *)BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
|
||||
}
|
||||
else if (node->type == CMP_NODE_COMPOSITE) {
|
||||
if (was_output == 0) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (node_iter->type == CMP_NODE_COMPOSITE) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
node->flag |= NODE_DO_OUTPUT;
|
||||
BKE_ntree_update_tag_active_output_changed(ntree);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
}
|
||||
else if (do_update) {
|
||||
BKE_ntree_update_tag_active_output_changed(ntree);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
}
|
||||
else if (ntree->type == NTREE_TEXTURE) {
|
||||
/* XXX */
|
||||
#if 0
|
||||
if (node->id) {
|
||||
BIF_preview_changed(-1);
|
||||
allqueue(REDRAWBUTSSHADING, 1);
|
||||
allqueue(REDRAWIPO, 0);
|
||||
}
|
||||
#endif
|
||||
else if (do_update) {
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
else if (ntree->type == NTREE_GEOMETRY) {
|
||||
if (node->type == GEO_NODE_VIEWER) {
|
||||
if ((node->flag & NODE_DO_OUTPUT) == 0) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (node_iter->type == GEO_NODE_VIEWER) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
}
|
||||
else if (ntree->type == NTREE_GEOMETRY) {
|
||||
if (node->type == GEO_NODE_VIEWER) {
|
||||
if ((node->flag & NODE_DO_OUTPUT) == 0) {
|
||||
for (bNode *node_iter : ntree->all_nodes()) {
|
||||
if (node_iter->type == GEO_NODE_VIEWER) {
|
||||
node_iter->flag &= ~NODE_DO_OUTPUT;
|
||||
}
|
||||
node->flag |= NODE_DO_OUTPUT;
|
||||
}
|
||||
blender::ed::viewer_path::activate_geometry_node(*bmain, *snode, *node);
|
||||
node->flag |= NODE_DO_OUTPUT;
|
||||
}
|
||||
blender::ed::viewer_path::activate_geometry_node(*bmain, *snode, *node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "DEG_depsgraph_build.h"
|
||||
|
||||
#include "ED_node.h" /* own include */
|
||||
#include "ED_node.hh"
|
||||
#include "ED_render.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
|
|
|
@ -183,7 +183,6 @@ void node_keymap(wmKeyConfig *keyconf);
|
|||
rctf node_frame_rect_inside(const bNode &node);
|
||||
bool node_or_socket_isect_event(const bContext &C, const wmEvent &event);
|
||||
|
||||
VectorSet<bNode *> get_selected_nodes(bNodeTree &node_tree);
|
||||
void node_deselect_all(SpaceNode &snode);
|
||||
void node_socket_select(bNode *node, bNodeSocket &sock);
|
||||
void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node);
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
#include "BKE_node_tree_update.h"
|
||||
#include "BKE_workspace.h"
|
||||
|
||||
#include "ED_node.h" /* own include */
|
||||
#include "ED_node.h" /* own include */
|
||||
#include "ED_node.hh" /* own include */
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_view3d.h"
|
||||
|
|
|
@ -524,7 +524,7 @@ static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, const w
|
|||
const int snap_on = data_intern->snap_on;
|
||||
|
||||
wmKeyMap *keymap = WM_keymap_active(wm, data_intern->keymap);
|
||||
for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
|
||||
LISTBASE_FOREACH (const wmKeyMapItem *, kmi, &keymap->items) {
|
||||
if (kmi->flag & KMI_INACTIVE) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -534,27 +534,6 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
|
|||
/* XXX(ton): temp, first hack to get auto-render in compositor work. */
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
|
||||
}
|
||||
|
||||
#if 0 /* TRANSFORM_FIX_ME */
|
||||
if (t->spacetype == SPACE_VIEW3D) {
|
||||
allqueue(REDRAWBUTSOBJECT, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
else if (t->spacetype == SPACE_IMAGE) {
|
||||
allqueue(REDRAWIMAGE, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_GRAPH)) {
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
allqueue(REDRAWACTION, 0);
|
||||
allqueue(REDRAWNLA, 0);
|
||||
allqueue(REDRAWIPO, 0);
|
||||
allqueue(REDRAWTIME, 0);
|
||||
allqueue(REDRAWBUTSOBJECT, 0);
|
||||
}
|
||||
|
||||
scrarea_queue_headredraw(curarea);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ************************************************* */
|
||||
|
@ -1336,7 +1315,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
|
|||
|
||||
t->state = TRANS_RUNNING;
|
||||
|
||||
/* avoid calculating PET */
|
||||
/* Avoid calculating proportional editing. */
|
||||
t->options = CTX_NO_PET;
|
||||
|
||||
t->mode = TFM_DUMMY;
|
||||
|
@ -1859,9 +1838,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
|||
* lead to keymap conflicts for other modes (see T31584)
|
||||
*/
|
||||
if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
|
||||
wmKeyMapItem *kmi;
|
||||
|
||||
for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) {
|
||||
LISTBASE_FOREACH (const wmKeyMapItem *, kmi, &t->keymap->items) {
|
||||
if (kmi->flag & KMI_INACTIVE) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -23,10 +23,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* use node center for transform instead of upper-left corner.
|
||||
* disabled since it makes absolute snapping not work so nicely
|
||||
*/
|
||||
// #define USE_NODE_CENTER
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Types/
|
||||
|
|
|
@ -709,7 +709,7 @@ static int countAndCleanTransDataContainer(TransInfo *t)
|
|||
|
||||
static void init_proportional_edit(TransInfo *t)
|
||||
{
|
||||
/* NOTE: PET is not usable in pose mode yet T32444. */
|
||||
/* NOTE: Proportional editing is not usable in pose mode yet T32444. */
|
||||
if (!ELEM(t->data_type,
|
||||
&TransConvertType_Action,
|
||||
&TransConvertType_Curve,
|
||||
|
@ -726,7 +726,7 @@ static void init_proportional_edit(TransInfo *t)
|
|||
&TransConvertType_Node,
|
||||
&TransConvertType_Object,
|
||||
&TransConvertType_Particle)) {
|
||||
/* Disable PET */
|
||||
/* Disable proportional editing */
|
||||
t->options |= CTX_NO_PET;
|
||||
t->flag &= ~T_PROP_EDIT_ALL;
|
||||
return;
|
||||
|
@ -1070,87 +1070,75 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
|
|||
{
|
||||
Object *ob = tc->obedit;
|
||||
ModifierData *md = ob->modifiers.first;
|
||||
float tolerance[3] = {0.0f, 0.0f, 0.0f};
|
||||
int axis = 0;
|
||||
|
||||
for (; md; md = md->next) {
|
||||
if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
|
||||
MirrorModifierData *mmd = (MirrorModifierData *)md;
|
||||
|
||||
if (mmd->flag & MOD_MIR_CLIPPING) {
|
||||
axis = 0;
|
||||
if (mmd->flag & MOD_MIR_AXIS_X) {
|
||||
axis |= 1;
|
||||
tolerance[0] = mmd->tolerance;
|
||||
if ((mmd->flag & MOD_MIR_CLIPPING) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((mmd->flag & (MOD_MIR_AXIS_X | MOD_MIR_AXIS_Y | MOD_MIR_AXIS_Y)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float mtx[4][4], imtx[4][4];
|
||||
|
||||
if (mmd->mirror_ob) {
|
||||
float obinv[4][4];
|
||||
|
||||
invert_m4_m4(obinv, mmd->mirror_ob->object_to_world);
|
||||
mul_m4_m4m4(mtx, obinv, ob->object_to_world);
|
||||
invert_m4_m4(imtx, mtx);
|
||||
}
|
||||
|
||||
TransData *td = tc->data;
|
||||
for (int i = 0; i < tc->data_len; i++, td++) {
|
||||
float loc[3], iloc[3];
|
||||
|
||||
if (td->loc == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
copy_v3_v3(loc, td->loc);
|
||||
copy_v3_v3(iloc, td->iloc);
|
||||
|
||||
if (mmd->mirror_ob) {
|
||||
mul_m4_v3(mtx, loc);
|
||||
mul_m4_v3(mtx, iloc);
|
||||
}
|
||||
|
||||
bool is_clipping = false;
|
||||
if (mmd->flag & MOD_MIR_AXIS_X) {
|
||||
if (fabsf(iloc[0]) <= mmd->tolerance || loc[0] * iloc[0] < 0.0f) {
|
||||
loc[0] = 0.0f;
|
||||
is_clipping = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mmd->flag & MOD_MIR_AXIS_Y) {
|
||||
axis |= 2;
|
||||
tolerance[1] = mmd->tolerance;
|
||||
if (fabsf(iloc[1]) <= mmd->tolerance || loc[1] * iloc[1] < 0.0f) {
|
||||
loc[1] = 0.0f;
|
||||
is_clipping = true;
|
||||
}
|
||||
}
|
||||
if (mmd->flag & MOD_MIR_AXIS_Z) {
|
||||
axis |= 4;
|
||||
tolerance[2] = mmd->tolerance;
|
||||
if (fabsf(iloc[2]) <= mmd->tolerance || loc[2] * iloc[2] < 0.0f) {
|
||||
loc[2] = 0.0f;
|
||||
is_clipping = true;
|
||||
}
|
||||
}
|
||||
if (axis) {
|
||||
float mtx[4][4], imtx[4][4];
|
||||
int i;
|
||||
|
||||
if (is_clipping) {
|
||||
if (mmd->mirror_ob) {
|
||||
float obinv[4][4];
|
||||
|
||||
invert_m4_m4(obinv, mmd->mirror_ob->object_to_world);
|
||||
mul_m4_m4m4(mtx, obinv, ob->object_to_world);
|
||||
invert_m4_m4(imtx, mtx);
|
||||
}
|
||||
|
||||
TransData *td = tc->data;
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
int clip;
|
||||
float loc[3], iloc[3];
|
||||
|
||||
if (td->loc == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
copy_v3_v3(loc, td->loc);
|
||||
copy_v3_v3(iloc, td->iloc);
|
||||
|
||||
if (mmd->mirror_ob) {
|
||||
mul_m4_v3(mtx, loc);
|
||||
mul_m4_v3(mtx, iloc);
|
||||
}
|
||||
|
||||
clip = 0;
|
||||
if (axis & 1) {
|
||||
if (fabsf(iloc[0]) <= tolerance[0] || loc[0] * iloc[0] < 0.0f) {
|
||||
loc[0] = 0.0f;
|
||||
clip = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (axis & 2) {
|
||||
if (fabsf(iloc[1]) <= tolerance[1] || loc[1] * iloc[1] < 0.0f) {
|
||||
loc[1] = 0.0f;
|
||||
clip = 1;
|
||||
}
|
||||
}
|
||||
if (axis & 4) {
|
||||
if (fabsf(iloc[2]) <= tolerance[2] || loc[2] * iloc[2] < 0.0f) {
|
||||
loc[2] = 0.0f;
|
||||
clip = 1;
|
||||
}
|
||||
}
|
||||
if (clip) {
|
||||
if (mmd->mirror_ob) {
|
||||
mul_m4_v3(imtx, loc);
|
||||
}
|
||||
copy_v3_v3(td->loc, loc);
|
||||
}
|
||||
mul_m4_v3(imtx, loc);
|
||||
}
|
||||
copy_v3_v3(td->loc, loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,7 +131,8 @@ static void createTransCurveVerts(bContext *UNUSED(C), TransInfo *t)
|
|||
}
|
||||
}
|
||||
|
||||
/* Support other objects using PET to adjust these, unless connected is enabled. */
|
||||
/* Support other objects using proportional editing to adjust these, unless connected is
|
||||
* enabled. */
|
||||
if (((is_prop_edit && !is_prop_connected) ? count : countsel) == 0) {
|
||||
tc->data_len = 0;
|
||||
continue;
|
||||
|
|
|
@ -52,7 +52,8 @@ static void createTransLatticeVerts(bContext *UNUSED(C), TransInfo *t)
|
|||
bp++;
|
||||
}
|
||||
|
||||
/* Support other objects using PET to adjust these, unless connected is enabled. */
|
||||
/* Support other objects using proportional editing to adjust these, unless connected is
|
||||
* enabled. */
|
||||
if (((is_prop_edit && !is_prop_connected) ? count : countsel) == 0) {
|
||||
tc->data_len = 0;
|
||||
continue;
|
||||
|
|
|
@ -44,7 +44,8 @@ static void createTransMBallVerts(bContext *UNUSED(C), TransInfo *t)
|
|||
}
|
||||
}
|
||||
|
||||
/* Support other objects using PET to adjust these, unless connected is enabled. */
|
||||
/* Support other objects using proportional editing to adjust these, unless connected is
|
||||
* enabled. */
|
||||
if (((is_prop_edit && !is_prop_connected) ? count : countsel) == 0) {
|
||||
tc->data_len = 0;
|
||||
continue;
|
||||
|
|
|
@ -843,7 +843,8 @@ void transform_convert_mesh_islands_calc(struct BMEditMesh *em,
|
|||
MEM_freeN(group_index);
|
||||
}
|
||||
|
||||
/* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
|
||||
/* for proportional editing we need islands of 1 so connected vertices can use it with
|
||||
* V3D_AROUND_LOCAL_ORIGINS */
|
||||
if (calc_single_islands) {
|
||||
BMIter viter;
|
||||
BMVert *v;
|
||||
|
@ -1484,7 +1485,8 @@ static void createTransEditVerts(bContext *UNUSED(C), TransInfo *t)
|
|||
* transform data is created by selected vertices.
|
||||
*/
|
||||
|
||||
/* Support other objects using PET to adjust these, unless connected is enabled. */
|
||||
/* Support other objects using proportional editing to adjust these, unless connected is
|
||||
* enabled. */
|
||||
if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -94,7 +94,8 @@ static void createTransMeshSkin(bContext *UNUSED(C), TransInfo *t)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Support other objects using PET to adjust these, unless connected is enabled. */
|
||||
/* Support other objects using proportional editing to adjust these, unless connected is
|
||||
* enabled. */
|
||||
if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -314,7 +314,8 @@ static void createTransUVs(bContext *C, TransInfo *t)
|
|||
|
||||
float *prop_dists = NULL;
|
||||
|
||||
/* Support other objects using PET to adjust these, unless connected is enabled. */
|
||||
/* Support other objects using proportional editing to adjust these, unless connected is
|
||||
* enabled. */
|
||||
if (((is_prop_edit && !is_prop_connected) ? count : countsel) == 0) {
|
||||
goto finally;
|
||||
}
|
||||
|
|
|
@ -77,7 +77,8 @@ static void createTransMeshVertCData(bContext *UNUSED(C), TransInfo *t)
|
|||
struct TransMirrorData mirror_data = {NULL};
|
||||
struct TransMeshDataCrazySpace crazyspace_data = {NULL};
|
||||
|
||||
/* Support other objects using PET to adjust these, unless connected is enabled. */
|
||||
/* Support other objects using proportional editing to adjust these, unless connected is
|
||||
* enabled. */
|
||||
if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_rect.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
@ -39,58 +39,55 @@ struct TransCustomDataNode {
|
|||
/** \name Node Transform Creation
|
||||
* \{ */
|
||||
|
||||
/* transcribe given node into TransData2D for Transforming */
|
||||
static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node, const float dpi_fac)
|
||||
static void create_transform_data_for_node(TransData &td,
|
||||
TransData2D &td2d,
|
||||
bNode &node,
|
||||
const float dpi_fac)
|
||||
{
|
||||
float locx, locy;
|
||||
|
||||
/* account for parents (nested nodes) */
|
||||
if (node->parent) {
|
||||
nodeToView(node->parent, node->locx, node->locy, &locx, &locy);
|
||||
if (node.parent) {
|
||||
nodeToView(node.parent, node.locx, node.locy, &locx, &locy);
|
||||
}
|
||||
else {
|
||||
locx = node->locx;
|
||||
locy = node->locy;
|
||||
locx = node.locx;
|
||||
locy = node.locy;
|
||||
}
|
||||
|
||||
/* use top-left corner as the transform origin for nodes */
|
||||
/* Weirdo - but the node system is a mix of free 2d elements and DPI sensitive UI. */
|
||||
#ifdef USE_NODE_CENTER
|
||||
td2d->loc[0] = (locx * dpi_fac) + (BLI_rctf_size_x(&node->runtime->totr) * +0.5f);
|
||||
td2d->loc[1] = (locy * dpi_fac) + (BLI_rctf_size_y(&node->runtime->totr) * -0.5f);
|
||||
#else
|
||||
td2d->loc[0] = locx * dpi_fac;
|
||||
td2d->loc[1] = locy * dpi_fac;
|
||||
#endif
|
||||
td2d->loc[2] = 0.0f;
|
||||
td2d->loc2d = td2d->loc; /* current location */
|
||||
td2d.loc[0] = locx * dpi_fac;
|
||||
td2d.loc[1] = locy * dpi_fac;
|
||||
td2d.loc[2] = 0.0f;
|
||||
td2d.loc2d = td2d.loc; /* current location */
|
||||
|
||||
td->loc = td2d->loc;
|
||||
copy_v3_v3(td->iloc, td->loc);
|
||||
td.loc = td2d.loc;
|
||||
copy_v3_v3(td.iloc, td.loc);
|
||||
/* use node center instead of origin (top-left corner) */
|
||||
td->center[0] = td2d->loc[0];
|
||||
td->center[1] = td2d->loc[1];
|
||||
td->center[2] = 0.0f;
|
||||
td.center[0] = td2d.loc[0];
|
||||
td.center[1] = td2d.loc[1];
|
||||
td.center[2] = 0.0f;
|
||||
|
||||
memset(td->axismtx, 0, sizeof(td->axismtx));
|
||||
td->axismtx[2][2] = 1.0f;
|
||||
memset(td.axismtx, 0, sizeof(td.axismtx));
|
||||
td.axismtx[2][2] = 1.0f;
|
||||
|
||||
td->ext = nullptr;
|
||||
td->val = nullptr;
|
||||
td.ext = nullptr;
|
||||
td.val = nullptr;
|
||||
|
||||
td->flag = TD_SELECTED;
|
||||
td->dist = 0.0f;
|
||||
td.flag = TD_SELECTED;
|
||||
td.dist = 0.0f;
|
||||
|
||||
unit_m3(td->mtx);
|
||||
unit_m3(td->smtx);
|
||||
unit_m3(td.mtx);
|
||||
unit_m3(td.smtx);
|
||||
|
||||
td->extra = node;
|
||||
td.extra = &node;
|
||||
}
|
||||
|
||||
static bool is_node_parent_select(bNode *node)
|
||||
static bool is_node_parent_select(const bNode *node)
|
||||
{
|
||||
while ((node = node->parent)) {
|
||||
if (node->flag & NODE_TRANSFORM) {
|
||||
if (node->flag & NODE_SELECT) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -99,8 +96,13 @@ static bool is_node_parent_select(bNode *node)
|
|||
|
||||
static void createTransNodeData(bContext * /*C*/, TransInfo *t)
|
||||
{
|
||||
const float dpi_fac = UI_DPI_FAC;
|
||||
using namespace blender;
|
||||
using namespace blender::ed;
|
||||
SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first);
|
||||
bNodeTree *node_tree = snode->edittree;
|
||||
if (!node_tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Custom data to enable edge panning during the node transform */
|
||||
TransCustomDataNode *customdata = MEM_cnew<TransCustomDataNode>(__func__);
|
||||
|
@ -119,37 +121,21 @@ static void createTransNodeData(bContext * /*C*/, TransInfo *t)
|
|||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
|
||||
tc->data_len = 0;
|
||||
|
||||
if (!snode->edittree) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Nodes don't support PET and probably never will. */
|
||||
/* Nodes don't support proportional editing and probably never will. */
|
||||
t->flag = t->flag & ~T_PROP_EDIT_ALL;
|
||||
|
||||
/* set transform flags on nodes */
|
||||
for (bNode *node : snode->edittree->all_nodes()) {
|
||||
if (node->flag & NODE_SELECT && !is_node_parent_select(node)) {
|
||||
node->flag |= NODE_TRANSFORM;
|
||||
tc->data_len++;
|
||||
}
|
||||
else {
|
||||
node->flag &= ~NODE_TRANSFORM;
|
||||
}
|
||||
}
|
||||
|
||||
if (tc->data_len == 0) {
|
||||
VectorSet<bNode *> nodes = space_node::get_selected_nodes(*node_tree);
|
||||
nodes.remove_if([&](bNode *node) { return is_node_parent_select(node); });
|
||||
if (nodes.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TransData *td = tc->data = MEM_cnew_array<TransData>(tc->data_len, __func__);
|
||||
TransData2D *td2d = tc->data_2d = MEM_cnew_array<TransData2D>(tc->data_len, __func__);
|
||||
tc->data_len = nodes.size();
|
||||
tc->data = MEM_cnew_array<TransData>(tc->data_len, __func__);
|
||||
tc->data_2d = MEM_cnew_array<TransData2D>(tc->data_len, __func__);
|
||||
|
||||
for (bNode *node : snode->edittree->all_nodes()) {
|
||||
if (node->flag & NODE_TRANSFORM) {
|
||||
NodeToTransData(td++, td2d++, node, dpi_fac);
|
||||
}
|
||||
for (const int i : nodes.index_range()) {
|
||||
create_transform_data_for_node(tc->data[i], tc->data_2d[i], *nodes[i], UI_DPI_FAC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,43 +147,41 @@ static void createTransNodeData(bContext * /*C*/, TransInfo *t)
|
|||
|
||||
static void node_snap_grid_apply(TransInfo *t)
|
||||
{
|
||||
int i;
|
||||
using namespace blender;
|
||||
|
||||
if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
float grid_size[2];
|
||||
copy_v2_v2(grid_size, t->snap_spatial);
|
||||
float2 grid_size = t->snap_spatial;
|
||||
if (t->modifiers & MOD_PRECISION) {
|
||||
mul_v2_fl(grid_size, t->snap_spatial_precision);
|
||||
grid_size *= t->snap_spatial_precision;
|
||||
}
|
||||
|
||||
/* Early exit on unusable grid size. */
|
||||
if (is_zero_v2(grid_size)) {
|
||||
if (math::is_zero(grid_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td;
|
||||
|
||||
for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
|
||||
for (const int i : IndexRange(tc->data_len)) {
|
||||
TransData &td = tc->data[i];
|
||||
float iloc[2], loc[2], tvec[2];
|
||||
if (td->flag & TD_SKIP) {
|
||||
if (td.flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
|
||||
if ((t->flag & T_PROP_EDIT) && (td.factor == 0.0f)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
copy_v2_v2(iloc, td->loc);
|
||||
copy_v2_v2(iloc, td.loc);
|
||||
|
||||
loc[0] = roundf(iloc[0] / grid_size[0]) * grid_size[0];
|
||||
loc[1] = roundf(iloc[1] / grid_size[1]) * grid_size[1];
|
||||
|
||||
sub_v2_v2v2(tvec, loc, iloc);
|
||||
add_v2_v2(td->loc, tvec);
|
||||
add_v2_v2(td.loc, tvec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -246,11 +230,6 @@ static void flushTransNodes(TransInfo *t)
|
|||
float loc[2];
|
||||
add_v2_v2v2(loc, td2d->loc, offset);
|
||||
|
||||
#ifdef USE_NODE_CENTER
|
||||
loc[0] -= 0.5f * BLI_rctf_size_x(&node->runtime->totr);
|
||||
loc[1] += 0.5f * BLI_rctf_size_y(&node->runtime->totr);
|
||||
#endif
|
||||
|
||||
/* Weirdo - but the node system is a mix of free 2d elements and DPI sensitive UI. */
|
||||
loc[0] /= dpi_fac;
|
||||
loc[1] /= dpi_fac;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue