Merge branch 'refactor-mesh-position-generic' into refactor-mesh-corners-generic

This commit is contained in:
Hans Goudey 2022-12-13 17:11:13 -06:00
commit 8e2dae3f8d
151 changed files with 2780 additions and 1413 deletions

View File

@ -12,7 +12,6 @@ if(UNIX)
automake
bison
${_libtoolize_name}
meson
ninja
pkg-config
tclsh

View File

@ -26,5 +26,6 @@ endif()
add_dependencies(
external_epoxy
# Needed for `MESON`.
external_python_site_packages
)

View File

@ -18,6 +18,7 @@ ExternalProject_Add(external_fribidi
add_dependencies(
external_fribidi
external_python
# Needed for `MESON`.
external_python_site_packages
)

View File

@ -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
)

View File

@ -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}*")

View File

@ -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
)

View File

@ -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.

View File

@ -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)

View File

@ -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}

View File

@ -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)

View File

@ -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

View File

@ -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
)

View File

@ -15,4 +15,6 @@ ExternalProject_Add(external_wayland_protocols
add_dependencies(
external_wayland_protocols
external_wayland
# Needed for `MESON`.
external_python_site_packages
)

View File

@ -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',

View File

@ -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)

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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 emitters axis would form with the direction to the shading point,
* cos(theta') in the paper */
/* Minimum angle an emitters 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 &centroid,
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;

View File

@ -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++) {

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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 */

View File

@ -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"

View File

@ -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'},

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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;

View File

@ -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.

View File

@ -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
)

View File

@ -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) {

View File

@ -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`.

View File

@ -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.
*/

View File

@ -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]--;
}
}

View File

@ -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;

View File

@ -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()] !=

View File

@ -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:

View File

@ -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) {

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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 {

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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
}

View File

@ -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) {

View File

@ -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);

View File

@ -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");

View File

@ -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

View File

@ -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()
{

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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. */

View File

@ -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.");
};

View File

@ -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 &region);
/**

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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 &region, 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 &region)
{
using namespace blender;
GPU_matrix_push_projection();
wmOrtho2_region_pixelspace(&region);
@ -3042,7 +3039,7 @@ static void draw_tree_path(const bContext &C, ARegion &region)
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);
}

View File

@ -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);
}
}
}

View File

@ -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"

View File

@ -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);

View File

@ -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"

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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/

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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