Sculpt: Add Transform, Trim, and Mesh Filter operators to Sculpt menu #104718
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"project_id" : "Blender",
|
||||
"conduit_uri" : "https://developer.blender.org/",
|
||||
"phabricator.uri" : "https://developer.blender.org/",
|
||||
"git.default-relative-commit" : "origin/master",
|
||||
"arc.land.update.default" : "rebase",
|
||||
"arc.land.onto.default" : "master"
|
||||
}
|
|
@ -299,7 +299,11 @@ else
|
|||
ifneq ("$(wildcard $(DEPS_BUILD_DIR)/build.ninja)","")
|
||||
DEPS_BUILD_COMMAND:=ninja
|
||||
else
|
||||
DEPS_BUILD_COMMAND:=make -s
|
||||
ifeq ($(OS), Darwin)
|
||||
DEPS_BUILD_COMMAND:=make -s
|
||||
else
|
||||
DEPS_BUILD_COMMAND:="$(BLENDER_DIR)/build_files/build_environment/linux/make_deps_wrapper.sh" -s
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -398,7 +402,7 @@ endif
|
|||
|
||||
deps: .FORCE
|
||||
@echo
|
||||
@echo Configuring dependencies in \"$(DEPS_BUILD_DIR)\"
|
||||
@echo Configuring dependencies in \"$(DEPS_BUILD_DIR)\", install to \"$(DEPS_INSTALL_DIR)\"
|
||||
|
||||
@cmake -H"$(DEPS_SOURCE_DIR)" \
|
||||
-B"$(DEPS_BUILD_DIR)" \
|
||||
|
|
|
@ -10,7 +10,7 @@ ExternalProject_Add(external_epoxy
|
|||
URL_HASH ${EPOXY_HASH_TYPE}=${EPOXY_HASH}
|
||||
PREFIX ${BUILD_DIR}/epoxy
|
||||
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/epoxy/src/external_epoxy/ < ${PATCH_DIR}/epoxy.diff
|
||||
CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${MESON} setup --prefix ${LIBDIR}/epoxy --default-library ${EPOXY_LIB_TYPE} --libdir lib ${BUILD_DIR}/epoxy/src/external_epoxy-build ${BUILD_DIR}/epoxy/src/external_epoxy -Dtests=false
|
||||
CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${MESON} setup --prefix ${LIBDIR}/epoxy --default-library ${EPOXY_LIB_TYPE} --libdir lib ${BUILD_DIR}/epoxy/src/external_epoxy-build ${BUILD_DIR}/epoxy/src/external_epoxy -Dtests=false ${MESON_BUILD_TYPE}
|
||||
BUILD_COMMAND ninja
|
||||
INSTALL_COMMAND ninja install
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@ ExternalProject_Add(external_fribidi
|
|||
URL_HASH ${FRIBIDI_HASH_TYPE}=${FRIBIDI_HASH}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
PREFIX ${BUILD_DIR}/fribidi
|
||||
CONFIGURE_COMMAND ${MESON} setup --prefix ${LIBDIR}/fribidi -Ddocs=false --default-library static --libdir lib ${BUILD_DIR}/fribidi/src/external_fribidi-build ${BUILD_DIR}/fribidi/src/external_fribidi
|
||||
CONFIGURE_COMMAND ${MESON} setup --prefix ${LIBDIR}/fribidi ${MESON_BUILD_TYPE} -Ddocs=false --default-library static --libdir lib ${BUILD_DIR}/fribidi/src/external_fribidi-build ${BUILD_DIR}/fribidi/src/external_fribidi
|
||||
BUILD_COMMAND ninja
|
||||
INSTALL_COMMAND ninja install
|
||||
INSTALL_DIR ${LIBDIR}/fribidi
|
||||
|
|
|
@ -21,6 +21,7 @@ set(HARFBUZZ_EXTRA_OPTIONS
|
|||
# Only used for command line utilities,
|
||||
# disable as this would add an addition & unnecessary build-dependency.
|
||||
-Dcairo=disabled
|
||||
${MESON_BUILD_TYPE}
|
||||
)
|
||||
|
||||
ExternalProject_Add(external_harfbuzz
|
||||
|
@ -59,3 +60,10 @@ if(BUILD_MODE STREQUAL Release AND WIN32)
|
|||
DEPENDEES install
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_MODE STREQUAL Debug AND WIN32)
|
||||
ExternalProject_Add_Step(external_harfbuzz after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/harfbuzz/lib/libharfbuzz.a ${HARVEST_TARGET}/harfbuzz/lib/libharfbuzz_d.lib
|
||||
DEPENDEES install
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -15,7 +15,7 @@ llvm-config = '${LIBDIR}/llvm/bin/llvm-config'"
|
|||
)
|
||||
|
||||
set(MESA_EXTRA_FLAGS
|
||||
-Dbuildtype=release
|
||||
${MESON_BUILD_TYPE}
|
||||
-Dc_args=${MESA_CFLAGS}
|
||||
-Dcpp_args=${MESA_CXXFLAGS}
|
||||
-Dc_link_args=${MESA_LDFLAGS}
|
||||
|
|
|
@ -16,8 +16,10 @@ message("BuildMode = ${BUILD_MODE}")
|
|||
|
||||
if(BUILD_MODE STREQUAL "Debug")
|
||||
set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Debug)
|
||||
set(MESON_BUILD_TYPE -Dbuildtype=debug)
|
||||
else()
|
||||
set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Release)
|
||||
set(MESON_BUILD_TYPE -Dbuildtype=release)
|
||||
endif()
|
||||
|
||||
set(DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/downloads" CACHE STRING "Path for downloaded files")
|
||||
|
|
|
@ -13,7 +13,7 @@ ExternalProject_Add(external_wayland
|
|||
# NOTE: `-lm` is needed for `libxml2` which is a static library that uses `libm.so`,
|
||||
# without this, math symbols such as `floor` aren't found.
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:${LIBDIR}/ffi/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||
${MESON} --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -D "c_link_args=-L${LIBDIR}/ffi/lib -lm" . ../external_wayland
|
||||
${MESON} --prefix ${LIBDIR}/wayland ${MESON_BUILD_TYPE} -Ddocumentation=false -Dtests=false -D "c_link_args=-L${LIBDIR}/ffi/lib -lm" . ../external_wayland
|
||||
BUILD_COMMAND ninja
|
||||
INSTALL_COMMAND ninja install
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ ExternalProject_Add(external_wayland_protocols
|
|||
PREFIX ${BUILD_DIR}/wayland-protocols
|
||||
# Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own WAYLAND.
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/wayland/lib64/pkgconfig:$PKG_CONFIG_PATH
|
||||
${MESON} --prefix ${LIBDIR}/wayland-protocols . ../external_wayland_protocols -Dtests=false
|
||||
${MESON} --prefix ${LIBDIR}/wayland-protocols ${MESON_BUILD_TYPE} . ../external_wayland_protocols -Dtests=false
|
||||
BUILD_COMMAND ninja
|
||||
INSTALL_COMMAND ninja install
|
||||
)
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# This script ensures:
|
||||
# - One dependency is built at a time.
|
||||
# - That dependency uses all available cores.
|
||||
#
|
||||
# Without this, simply calling `make -j$(nproc)` from the `${CMAKE_BUILD_DIR}/deps/`
|
||||
# directory will build many projects at once.
|
||||
#
|
||||
# This is undesirable for the following reasons:
|
||||
#
|
||||
# - The output from projects is mixed together,
|
||||
# making it difficult to track down the cause of a build failure.
|
||||
#
|
||||
# - Larger dependencies such as LLVM can bottleneck the build process,
|
||||
# making it necessary to cancel the build and manually run build commands in each directory.
|
||||
#
|
||||
# - Building many projects at once means canceling (Control-C) can lead to the build being in an undefined state.
|
||||
# It's possible canceling happens as a patch is being applied or files are being copied.
|
||||
# (steps that aren't part of the compilation process where it's typically safe to cancel).
|
||||
|
||||
if [[ -z "$MY_MAKE_CALL_LEVEL" ]]; then
|
||||
export MY_MAKE_CALL_LEVEL=0
|
||||
export MY_MAKEFLAGS=$MAKEFLAGS
|
||||
|
||||
# Extract the jobs argument (`-jN`, `-j N`, `--jobs=N`).
|
||||
add_next=0
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
-j*)
|
||||
export MY_JOBS_ARG=$i
|
||||
if [ "$MY_JOBS_ARG" = "-j" ]; then
|
||||
add_next=1
|
||||
fi
|
||||
;;
|
||||
--jobs=*)
|
||||
shift # past argument=value
|
||||
MY_JOBS_ARG=$i
|
||||
;;
|
||||
*)
|
||||
if (( add_next == 1 )); then
|
||||
MY_JOBS_ARG="$MY_JOBS_ARG $i"
|
||||
add_next=0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
unset i add_next
|
||||
|
||||
if [[ -z "$MY_JOBS_ARG" ]]; then
|
||||
MY_JOBS_ARG="-j$(nproc)"
|
||||
fi
|
||||
export MY_JOBS_ARG
|
||||
# Support user defined `MAKEFLAGS`.
|
||||
export MAKEFLAGS="$MY_MAKEFLAGS -j1"
|
||||
else
|
||||
export MY_MAKE_CALL_LEVEL=$(( MY_MAKE_CALL_LEVEL + 1 ))
|
||||
if (( MY_MAKE_CALL_LEVEL == 1 )); then
|
||||
# Important to set jobs to 1, otherwise user defined jobs argument is used.
|
||||
export MAKEFLAGS="$MY_MAKEFLAGS -j1"
|
||||
elif (( MY_MAKE_CALL_LEVEL == 2 )); then
|
||||
# This is the level used by each sub-project.
|
||||
export MAKEFLAGS="$MY_MAKEFLAGS $MY_JOBS_ARG"
|
||||
fi
|
||||
# Else leave `MY_MAKEFLAGS` flags as-is, avoids setting a high number of jobs on recursive
|
||||
# calls (which may easily run out of memory). Let the job-server handle the rest.
|
||||
fi
|
||||
|
||||
# Useful for troubleshooting the wrapper.
|
||||
# echo "Call level: $MY_MAKE_CALL_LEVEL, args=$@".
|
||||
|
||||
# Call actual make but ensure recursive calls run via this script.
|
||||
exec make MAKE="$0" "$@"
|
|
@ -85,7 +85,7 @@ if(NOT APPLE)
|
|||
set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CYCLES_CUBIN_COMPILER OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_CYCLES_HIP_BINARIES ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CYCLES_HIP_BINARIES OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_CYCLES_DEVICE_ONEAPI ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CYCLES_ONEAPI_BINARIES ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
|
|
@ -295,7 +295,7 @@ unset(MATERIALX_LIB_FOLDER_EXISTS)
|
|||
if(NOT MSVC_CLANG AND # Available with MSVC 15.7+ but not for CLANG.
|
||||
NOT WITH_WINDOWS_SCCACHE AND # And not when sccache is enabled
|
||||
NOT VS_CLANG_TIDY) # Clang-tidy does not like these options
|
||||
add_compile_options(/experimental:external /external:templates- /external:I "${LIBDIR}" /external:W0)
|
||||
add_compile_options(/experimental:external /external:I "${LIBDIR}" /external:W0)
|
||||
endif()
|
||||
|
||||
# Add each of our libraries to our cmake_prefix_path so find_package() could work
|
||||
|
|
|
@ -38,7 +38,7 @@ PROJECT_NAME = Blender
|
|||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = V3.5
|
||||
PROJECT_NUMBER = V3.6
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
|
|
@ -487,7 +487,7 @@ BLENDER_VERSION_DOTS = "%d.%d" % (bpy.app.version[0], bpy.app.version[1])
|
|||
if BLENDER_REVISION != "Unknown":
|
||||
# SHA1 Git hash
|
||||
BLENDER_VERSION_HASH = BLENDER_REVISION
|
||||
BLENDER_VERSION_HASH_HTML_LINK = "<a href=https://developer.blender.org/rB%s>%s</a>" % (
|
||||
BLENDER_VERSION_HASH_HTML_LINK = "<a href=https://projects.blender.org/blender/blender/commit/%s>%s</a>" % (
|
||||
BLENDER_VERSION_HASH, BLENDER_VERSION_HASH,
|
||||
)
|
||||
BLENDER_VERSION_DATE = time.strftime("%d/%m/%Y", time.localtime(BLENDER_REVISION_TIMESTAMP))
|
||||
|
@ -647,7 +647,7 @@ def undocumented_message(module_name, type_name, identifier):
|
|||
module_name, type_name, identifier,
|
||||
)
|
||||
|
||||
return "Undocumented, consider `contributing <https://developer.blender.org/T51061>`__."
|
||||
return "Undocumented, consider `contributing <https://developer.blender.org/>`__."
|
||||
|
||||
|
||||
def range_str(val):
|
||||
|
|
|
@ -1676,17 +1676,20 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
col.label(text="and NVIDIA driver version %s or newer" % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif device_type == 'HIP':
|
||||
import sys
|
||||
if sys.platform[:3] == "win":
|
||||
driver_version = "21.Q4"
|
||||
col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif sys.platform.startswith("linux"):
|
||||
driver_version = "22.10"
|
||||
col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and AMD driver version %s or newer") % driver_version, icon='BLANK1',
|
||||
translate=False)
|
||||
if True:
|
||||
col.label(text="HIP temporarily disabled due to compiler bugs", icon='BLANK1')
|
||||
else:
|
||||
import sys
|
||||
if sys.platform[:3] == "win":
|
||||
driver_version = "21.Q4"
|
||||
col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and AMD Radeon Pro %s driver or newer") % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif sys.platform.startswith("linux"):
|
||||
driver_version = "22.10"
|
||||
col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
|
||||
col.label(text=iface_("and AMD driver version %s or newer") % driver_version, icon='BLANK1',
|
||||
translate=False)
|
||||
elif device_type == 'ONEAPI':
|
||||
import sys
|
||||
if sys.platform.startswith("win"):
|
||||
|
|
|
@ -94,7 +94,7 @@ void python_thread_state_restore(void **python_thread_state)
|
|||
*python_thread_state = NULL;
|
||||
}
|
||||
|
||||
static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
|
||||
static const char *PyC_UnicodeAsBytes(PyObject *py_str, PyObject **coerce)
|
||||
{
|
||||
const char *result = PyUnicode_AsUTF8(py_str);
|
||||
if (result) {
|
||||
|
@ -131,8 +131,8 @@ static PyObject *init_func(PyObject * /*self*/, PyObject *args)
|
|||
}
|
||||
|
||||
PyObject *path_coerce = nullptr, *user_path_coerce = nullptr;
|
||||
path_init(PyC_UnicodeAsByte(path, &path_coerce),
|
||||
PyC_UnicodeAsByte(user_path, &user_path_coerce));
|
||||
path_init(PyC_UnicodeAsBytes(path, &path_coerce),
|
||||
PyC_UnicodeAsBytes(user_path, &user_path_coerce));
|
||||
Py_XDECREF(path_coerce);
|
||||
Py_XDECREF(user_path_coerce);
|
||||
|
||||
|
|
|
@ -42,12 +42,15 @@ endif()
|
|||
###########################################################################
|
||||
|
||||
if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
|
||||
find_package(HIP)
|
||||
set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES)
|
||||
set(WITH_CYCLES_HIP_BINARIES OFF)
|
||||
message(STATUS "HIP temporarily disabled due to compiler bugs")
|
||||
|
||||
if(HIP_FOUND)
|
||||
message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})")
|
||||
endif()
|
||||
# find_package(HIP)
|
||||
# set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES)
|
||||
|
||||
# if(HIP_FOUND)
|
||||
# message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})")
|
||||
# endif()
|
||||
endif()
|
||||
|
||||
if(NOT WITH_HIP_DYNLOAD)
|
||||
|
|
|
@ -899,8 +899,8 @@ int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) c
|
|||
/* Schedule samples equal to the resolution divider up to a maximum of 4.
|
||||
* The idea is to have enough information on the screen by increasing the sample count as the
|
||||
* resolution is decreased. */
|
||||
/* NOTE: Changeing this formula will change the formula in
|
||||
* "RenderScheduler::calculate_resolution_divider_for_time()"*/
|
||||
/* NOTE: Changing this formula will change the formula in
|
||||
* `RenderScheduler::calculate_resolution_divider_for_time()`. */
|
||||
return min(max(1, resolution_divider / pixel_size_), 4);
|
||||
}
|
||||
|
||||
|
@ -1177,18 +1177,18 @@ int RenderScheduler::calculate_resolution_divider_for_time(double desired_time,
|
|||
{
|
||||
const double ratio_between_times = actual_time / desired_time;
|
||||
|
||||
/* We can pass "ratio_between_times" to "get_num_samples_during_navigation()" to get our
|
||||
/* We can pass `ratio_between_times` to `get_num_samples_during_navigation()` to get our
|
||||
* navigation samples because the equation for calculating the resolution divider is as follows:
|
||||
* "actual_time / desired_time = sqr(resolution_divider) / sample_count".
|
||||
* While "resolution_divider" is less than or equal to 4, "resolution_divider = sample_count"
|
||||
* (This relationship is determined in "get_num_samples_during_navigation()"). With some
|
||||
* substitution we end up with "actual_time / desired_time = resolution_divider" while the
|
||||
* `actual_time / desired_time = sqr(resolution_divider) / sample_count`.
|
||||
* While `resolution_divider` is less than or equal to 4, `resolution_divider = sample_count`
|
||||
* (This relationship is determined in `get_num_samples_during_navigation()`). With some
|
||||
* substitution we end up with `actual_time / desired_time = resolution_divider` while the
|
||||
* resolution divider is less than or equal to 4. Once the resolution divider increases above 4,
|
||||
* the relationsip of "actual_time / desired_time = resolution_divider" is no longer true,
|
||||
* however the sample count retrieved from "get_num_samples_during_navigation()" is still
|
||||
* the relationship of `actual_time / desired_time = resolution_divider` is no longer true,
|
||||
* however the sample count retrieved from `get_num_samples_during_navigation()` is still
|
||||
* accurate if we continue using this assumption. It should be noted that the interaction between
|
||||
* pixel_size, sample count, and resolution divider are automatically accounted for and that's
|
||||
* why pixel_size isn't included in any of the equations. */
|
||||
* `pixel_size`, sample count, and resolution divider are automatically accounted for and that's
|
||||
* why `pixel_size` isn't included in any of the equations. */
|
||||
const int navigation_samples = get_num_samples_during_navigation(
|
||||
ceil_to_int(ratio_between_times));
|
||||
|
||||
|
|
|
@ -276,6 +276,10 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
|
|||
ccl_private float2 *roughness,
|
||||
ccl_private float *eta)
|
||||
{
|
||||
#ifdef __SVM__
|
||||
bool refractive = false;
|
||||
float alpha = 1.0f;
|
||||
#endif
|
||||
switch (sc->type) {
|
||||
case CLOSURE_BSDF_DIFFUSE_ID:
|
||||
*roughness = one_float2();
|
||||
|
@ -287,13 +291,11 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
|
|||
*eta = 1.0f;
|
||||
break;
|
||||
# ifdef __OSL__
|
||||
case CLOSURE_BSDF_PHONG_RAMP_ID: {
|
||||
ccl_private const PhongRampBsdf *bsdf = (ccl_private const PhongRampBsdf *)sc;
|
||||
float alpha = phong_ramp_exponent_to_roughness(bsdf->exponent);
|
||||
case CLOSURE_BSDF_PHONG_RAMP_ID:
|
||||
alpha = phong_ramp_exponent_to_roughness(((ccl_private const PhongRampBsdf *)sc)->exponent);
|
||||
*roughness = make_float2(alpha, alpha);
|
||||
*eta = 1.0f;
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_DIFFUSE_RAMP_ID:
|
||||
*roughness = one_float2();
|
||||
*eta = 1.0f;
|
||||
|
@ -326,7 +328,7 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
|
|||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: {
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
*roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
|
||||
const bool refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
|
||||
refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
|
||||
*eta = refractive ? 1.0f / bsdf->ior : bsdf->ior;
|
||||
break;
|
||||
}
|
||||
|
@ -348,7 +350,7 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
|
|||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: {
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
*roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
|
||||
const bool refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
|
||||
refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
|
||||
*eta = refractive ? 1.0f / bsdf->ior : bsdf->ior;
|
||||
} break;
|
||||
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: {
|
||||
|
@ -380,12 +382,11 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
|
|||
((ccl_private HairBsdf *)sc)->roughness2);
|
||||
*eta = 1.0f;
|
||||
break;
|
||||
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: {
|
||||
ccl_private const PrincipledHairBSDF *bsdf = (ccl_private const PrincipledHairBSDF *)sc;
|
||||
*roughness = make_float2(bsdf->v_R, bsdf->v_R);
|
||||
*eta = bsdf->eta;
|
||||
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
|
||||
alpha = ((ccl_private PrincipledHairBSDF *)sc)->m0_roughness;
|
||||
*roughness = make_float2(alpha, alpha);
|
||||
*eta = ((ccl_private PrincipledHairBSDF *)sc)->eta;
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
|
||||
*roughness = one_float2();
|
||||
*eta = 1.0f;
|
||||
|
@ -685,7 +686,7 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
|
|||
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
|
||||
break;
|
||||
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
|
||||
albedo *= bsdf_principled_hair_albedo(sc);
|
||||
albedo *= bsdf_principled_hair_albedo(sd, sc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -13,11 +13,7 @@ CCL_NAMESPACE_BEGIN
|
|||
|
||||
typedef struct PrincipledHairExtra {
|
||||
/* Geometry data. */
|
||||
float3 Y, Z;
|
||||
float gamma_o, gamma_t;
|
||||
/* Precomputed Transmission and Fresnel term */
|
||||
Spectrum T;
|
||||
float f;
|
||||
float4 geom;
|
||||
} PrincipledHairExtra;
|
||||
|
||||
typedef struct PrincipledHairBSDF {
|
||||
|
@ -25,16 +21,16 @@ typedef struct PrincipledHairBSDF {
|
|||
|
||||
/* Absorption coefficient. */
|
||||
Spectrum sigma;
|
||||
/* Variance of the underlying logistic distribution, based on longitudinal roughness. */
|
||||
/* Variance of the underlying logistic distribution. */
|
||||
float v;
|
||||
/* Scale factor of the underlying logistic distribution, based on azimuthal roughness. */
|
||||
/* Scale factor of the underlying logistic distribution. */
|
||||
float s;
|
||||
/* Alternative value for v, used for the R lobe. */
|
||||
float v_R;
|
||||
/* Cuticle tilt angle. */
|
||||
float alpha;
|
||||
/* IOR. */
|
||||
float eta;
|
||||
/* Effective variance for the diffuse bounce only. */
|
||||
float m0_roughness;
|
||||
|
||||
/* Extra closure. */
|
||||
ccl_private PrincipledHairExtra *extra;
|
||||
|
@ -135,9 +131,6 @@ ccl_device_inline float sample_trimmed_logistic(float u, float s)
|
|||
ccl_device_inline float azimuthal_scattering(
|
||||
float phi, int p, float s, float gamma_o, float gamma_t)
|
||||
{
|
||||
if (p == 3) {
|
||||
return M_1_2PI_F;
|
||||
}
|
||||
float phi_o = wrap_angle(phi - delta_phi(p, gamma_o, gamma_t));
|
||||
float val = trimmed_logistic(phi_o, s);
|
||||
return val;
|
||||
|
@ -162,45 +155,27 @@ ccl_device_inline float longitudinal_scattering(
|
|||
}
|
||||
}
|
||||
|
||||
ccl_device_forceinline float hair_get_lobe_v(const ccl_private PrincipledHairBSDF *bsdf,
|
||||
const int lobe)
|
||||
{
|
||||
if (lobe == 0) {
|
||||
return bsdf->v_R;
|
||||
}
|
||||
else if (lobe == 1) {
|
||||
return 0.25f * bsdf->v;
|
||||
}
|
||||
else {
|
||||
return 4.0f * bsdf->v;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __HAIR__
|
||||
/* Set up the hair closure. */
|
||||
ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd,
|
||||
ccl_private PrincipledHairBSDF *bsdf,
|
||||
float u_rough,
|
||||
float u_coat_rough,
|
||||
float v_rough)
|
||||
ccl_private PrincipledHairBSDF *bsdf)
|
||||
{
|
||||
u_rough = clamp(u_rough, 0.001f, 1.0f);
|
||||
v_rough = clamp(v_rough, 0.001f, 1.0f);
|
||||
/* u_coat_rough is a multiplier that modifies u_rough for the R lobe. */
|
||||
float u_R_roughness = clamp(u_coat_rough * u_rough, 0.001f, 1.0f);
|
||||
|
||||
bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
|
||||
bsdf->v = clamp(bsdf->v, 0.001f, 1.0f);
|
||||
bsdf->s = clamp(bsdf->s, 0.001f, 1.0f);
|
||||
/* Apply Primary Reflection Roughness modifier. */
|
||||
bsdf->m0_roughness = clamp(bsdf->m0_roughness * bsdf->v, 0.001f, 1.0f);
|
||||
|
||||
/* Map from the azimuthal and the two longitudinal roughnesses to variance and scale factor. */
|
||||
bsdf->v = sqr(0.726f * u_rough + 0.812f * sqr(u_rough) + 3.700f * pow20(u_rough));
|
||||
bsdf->v_R = sqr(0.726f * u_R_roughness + 0.812f * sqr(u_R_roughness) +
|
||||
3.700f * pow20(u_R_roughness));
|
||||
bsdf->s = (0.265f * v_rough + 1.194f * sqr(v_rough) + 5.372f * pow22(v_rough)) * M_SQRT_PI_8_F;
|
||||
/* Map from roughness_u and roughness_v to variance and scale factor. */
|
||||
bsdf->v = sqr(0.726f * bsdf->v + 0.812f * sqr(bsdf->v) + 3.700f * pow20(bsdf->v));
|
||||
bsdf->s = (0.265f * bsdf->s + 1.194f * sqr(bsdf->s) + 5.372f * pow22(bsdf->s)) * M_SQRT_PI_8_F;
|
||||
bsdf->m0_roughness = sqr(0.726f * bsdf->m0_roughness + 0.812f * sqr(bsdf->m0_roughness) +
|
||||
3.700f * pow20(bsdf->m0_roughness));
|
||||
|
||||
/* Compute local frame, aligned to curve tangent and ray direction. */
|
||||
float3 X = safe_normalize(sd->dPdu);
|
||||
bsdf->extra->Y = safe_normalize(cross(X, sd->wi));
|
||||
bsdf->extra->Z = safe_normalize(cross(X, bsdf->extra->Y));
|
||||
float3 Y = safe_normalize(cross(X, sd->wi));
|
||||
float3 Z = safe_normalize(cross(X, Y));
|
||||
|
||||
/* h -1..0..1 means the rays goes from grazing the hair, to hitting it at
|
||||
* the center, to grazing the other edge. This is the sine of the angle
|
||||
|
@ -208,28 +183,13 @@ ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd,
|
|||
|
||||
/* TODO: we convert this value to a cosine later and discard the sign, so
|
||||
* we could probably save some operations. */
|
||||
float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : dot(cross(sd->Ng, X), bsdf->extra->Z);
|
||||
float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : dot(cross(sd->Ng, X), Z);
|
||||
|
||||
kernel_assert(fabsf(h) < 1.0f + 1e-4f);
|
||||
kernel_assert(isfinite_safe(Y));
|
||||
kernel_assert(isfinite_safe(h));
|
||||
|
||||
const float sin_theta_o = dot(sd->wi, X);
|
||||
const float cos_theta_o = cos_from_sin(sin_theta_o);
|
||||
|
||||
const float sin_theta_t = sin_theta_o / bsdf->eta;
|
||||
const float cos_theta_t = cos_from_sin(sin_theta_t);
|
||||
|
||||
const float sin_gamma_o = h;
|
||||
const float cos_gamma_o = cos_from_sin(sin_gamma_o);
|
||||
bsdf->extra->gamma_o = safe_asinf(sin_gamma_o);
|
||||
|
||||
const float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o));
|
||||
const float cos_gamma_t = cos_from_sin(sin_gamma_t);
|
||||
bsdf->extra->gamma_t = safe_asinf(sin_gamma_t);
|
||||
|
||||
bsdf->extra->T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
|
||||
bsdf->extra->f = fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta);
|
||||
bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h);
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION;
|
||||
}
|
||||
|
@ -238,35 +198,35 @@ ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd,
|
|||
|
||||
/* Given the Fresnel term and transmittance, generate the attenuation terms for each bounce. */
|
||||
ccl_device_inline void hair_attenuation(
|
||||
KernelGlobals kg, float f, Spectrum T, ccl_private Spectrum *Ap, ccl_private float *lobe_pdf)
|
||||
KernelGlobals kg, float f, Spectrum T, ccl_private Spectrum *Ap, ccl_private float *Ap_energy)
|
||||
{
|
||||
/* Primary specular (R). */
|
||||
Ap[0] = make_spectrum(f);
|
||||
lobe_pdf[0] = f;
|
||||
Ap_energy[0] = f;
|
||||
|
||||
/* Transmission (TT). */
|
||||
Spectrum col = sqr(1.0f - f) * T;
|
||||
Ap[1] = col;
|
||||
lobe_pdf[1] = spectrum_to_gray(kg, col);
|
||||
Ap_energy[1] = spectrum_to_gray(kg, col);
|
||||
|
||||
/* Secondary specular (TRT). */
|
||||
col *= T * f;
|
||||
Ap[2] = col;
|
||||
lobe_pdf[2] = spectrum_to_gray(kg, col);
|
||||
Ap_energy[2] = spectrum_to_gray(kg, col);
|
||||
|
||||
/* Residual component (TRRT+). */
|
||||
col *= safe_divide(T * f, one_spectrum() - T * f);
|
||||
Ap[3] = col;
|
||||
lobe_pdf[3] = spectrum_to_gray(kg, col);
|
||||
Ap_energy[3] = spectrum_to_gray(kg, col);
|
||||
|
||||
/* Normalize sampling weights. */
|
||||
float totweight = lobe_pdf[0] + lobe_pdf[1] + lobe_pdf[2] + lobe_pdf[3];
|
||||
float totweight = Ap_energy[0] + Ap_energy[1] + Ap_energy[2] + Ap_energy[3];
|
||||
float fac = safe_divide(1.0f, totweight);
|
||||
|
||||
lobe_pdf[0] *= fac;
|
||||
lobe_pdf[1] *= fac;
|
||||
lobe_pdf[2] *= fac;
|
||||
lobe_pdf[3] *= fac;
|
||||
Ap_energy[0] *= fac;
|
||||
Ap_energy[1] *= fac;
|
||||
Ap_energy[2] *= fac;
|
||||
Ap_energy[3] *= fac;
|
||||
}
|
||||
|
||||
/* Given the tilt angle, generate the rotated theta_i for the different bounces. */
|
||||
|
@ -288,120 +248,91 @@ ccl_device_inline void hair_alpha_angles(float sin_theta_i,
|
|||
angles[3] = fabsf(cos_theta_i * cos_1alpha + sin_theta_i * sin_1alpha);
|
||||
angles[4] = sin_theta_i * cos_4alpha - cos_theta_i * sin_4alpha;
|
||||
angles[5] = fabsf(cos_theta_i * cos_4alpha + sin_theta_i * sin_4alpha);
|
||||
angles[6] = sin_theta_i;
|
||||
angles[7] = cos_theta_i;
|
||||
}
|
||||
|
||||
/* Since most of the implementation is the same between sampling and evaluation,
|
||||
* this shared function implements both.
|
||||
* For evaluation, wo is an input, and randu/randv are ignored.
|
||||
* For sampling, wo is an output, and randu/randv are used to pick it.
|
||||
*/
|
||||
template<bool do_sample>
|
||||
ccl_device int bsdf_principled_hair_impl(KernelGlobals kg,
|
||||
ccl_private const PrincipledHairBSDF *bsdf,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private Spectrum *F,
|
||||
ccl_private float *pdf,
|
||||
float randu,
|
||||
float randv)
|
||||
{
|
||||
const float3 X = safe_normalize(sd->dPdu);
|
||||
const float3 Y = bsdf->extra->Y;
|
||||
const float3 Z = bsdf->extra->Z;
|
||||
kernel_assert(fabsf(dot(X, Y)) < 1e-3f);
|
||||
|
||||
const float gamma_o = bsdf->extra->gamma_o;
|
||||
const float gamma_t = bsdf->extra->gamma_t;
|
||||
|
||||
const float3 local_O = make_float3(dot(sd->wi, X), dot(sd->wi, Y), dot(sd->wi, Z));
|
||||
const float sin_theta_o = local_O.x;
|
||||
const float cos_theta_o = cos_from_sin(sin_theta_o);
|
||||
const float phi_o = atan2f(local_O.z, local_O.y);
|
||||
|
||||
Spectrum Ap[4];
|
||||
float lobe_pdf[4];
|
||||
hair_attenuation(kg, bsdf->extra->f, bsdf->extra->T, Ap, lobe_pdf);
|
||||
|
||||
float sin_theta_i, cos_theta_i, phi;
|
||||
int sampled_p = 0;
|
||||
if (do_sample) {
|
||||
/* Pick lobe for sampline */
|
||||
for (; sampled_p < 3; sampled_p++) {
|
||||
if (randu < lobe_pdf[sampled_p]) {
|
||||
break;
|
||||
}
|
||||
randu -= lobe_pdf[sampled_p];
|
||||
}
|
||||
|
||||
/* Sample incoming direction */
|
||||
float v = hair_get_lobe_v(bsdf, sampled_p);
|
||||
float randw = lcg_step_float(&sd->lcg_state), randx = lcg_step_float(&sd->lcg_state);
|
||||
randw = max(randw, 1e-5f);
|
||||
const float fac = 1.0f + v * logf(randw + (1.0f - randw) * expf(-2.0f / v));
|
||||
sin_theta_i = -fac * sin_theta_o + cos_from_sin(fac) * cosf(M_2PI_F * randx) * cos_theta_o;
|
||||
cos_theta_i = cos_from_sin(sin_theta_i);
|
||||
|
||||
if (sampled_p < 3) {
|
||||
float angles[8];
|
||||
hair_alpha_angles(sin_theta_i, cos_theta_i, -bsdf->alpha, angles);
|
||||
sin_theta_i = angles[2 * sampled_p];
|
||||
cos_theta_i = angles[2 * sampled_p + 1];
|
||||
|
||||
phi = delta_phi(sampled_p, gamma_o, gamma_t) + sample_trimmed_logistic(randv, bsdf->s);
|
||||
}
|
||||
else {
|
||||
phi = M_2PI_F * randv;
|
||||
}
|
||||
|
||||
const float phi_i = phi_o + phi;
|
||||
*wo = X * sin_theta_i + Y * cos_theta_i * cosf(phi_i) + Z * cos_theta_i * sinf(phi_i);
|
||||
}
|
||||
else {
|
||||
const float3 local_I = make_float3(dot(*wo, X), dot(*wo, Y), dot(*wo, Z));
|
||||
|
||||
sin_theta_i = local_I.x;
|
||||
cos_theta_i = cos_from_sin(sin_theta_i);
|
||||
|
||||
const float phi_i = atan2f(local_I.z, local_I.y);
|
||||
phi = phi_i - phi_o;
|
||||
}
|
||||
|
||||
/* Evaluate throughput. */
|
||||
float angles[8];
|
||||
hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles);
|
||||
|
||||
*F = zero_spectrum();
|
||||
*pdf = 0.0f;
|
||||
|
||||
for (int p = 0; p < 4; p++) {
|
||||
const float Mp = longitudinal_scattering(
|
||||
angles[2 * p], angles[2 * p + 1], sin_theta_o, cos_theta_o, hair_get_lobe_v(bsdf, p));
|
||||
const float Np = azimuthal_scattering(phi, p, bsdf->s, gamma_o, gamma_t);
|
||||
*F += Ap[p] * Mp * Np;
|
||||
*pdf += lobe_pdf[p] * Mp * Np;
|
||||
kernel_assert(isfinite_safe(*F) && isfinite_safe(*pdf));
|
||||
}
|
||||
|
||||
return sampled_p;
|
||||
}
|
||||
|
||||
/* Evaluation function for our shader. */
|
||||
ccl_device Spectrum bsdf_principled_hair_eval(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
float3 wo,
|
||||
const float3 wo,
|
||||
ccl_private float *pdf)
|
||||
{
|
||||
kernel_assert(isfinite_safe(sd->P) && isfinite_safe(sd->ray_length));
|
||||
|
||||
ccl_private const PrincipledHairBSDF *bsdf = (ccl_private const PrincipledHairBSDF *)sc;
|
||||
const float3 Y = float4_to_float3(bsdf->extra->geom);
|
||||
|
||||
Spectrum eval;
|
||||
bsdf_principled_hair_impl<false>(kg, bsdf, sd, &wo, &eval, pdf, 0.0f, 0.0f);
|
||||
return eval;
|
||||
const float3 X = safe_normalize(sd->dPdu);
|
||||
kernel_assert(fabsf(dot(X, Y)) < 1e-3f);
|
||||
const float3 Z = safe_normalize(cross(X, Y));
|
||||
|
||||
/* local_I is the illumination direction. */
|
||||
const float3 local_O = make_float3(dot(sd->wi, X), dot(sd->wi, Y), dot(sd->wi, Z));
|
||||
const float3 local_I = make_float3(dot(wo, X), dot(wo, Y), dot(wo, Z));
|
||||
|
||||
const float sin_theta_o = local_O.x;
|
||||
const float cos_theta_o = cos_from_sin(sin_theta_o);
|
||||
const float phi_o = atan2f(local_O.z, local_O.y);
|
||||
|
||||
const float sin_theta_t = sin_theta_o / bsdf->eta;
|
||||
const float cos_theta_t = cos_from_sin(sin_theta_t);
|
||||
|
||||
const float sin_gamma_o = bsdf->extra->geom.w;
|
||||
const float cos_gamma_o = cos_from_sin(sin_gamma_o);
|
||||
const float gamma_o = safe_asinf(sin_gamma_o);
|
||||
|
||||
const float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o));
|
||||
const float cos_gamma_t = cos_from_sin(sin_gamma_t);
|
||||
const float gamma_t = safe_asinf(sin_gamma_t);
|
||||
|
||||
const Spectrum T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
|
||||
Spectrum Ap[4];
|
||||
float Ap_energy[4];
|
||||
hair_attenuation(
|
||||
kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap, Ap_energy);
|
||||
|
||||
const float sin_theta_i = local_I.x;
|
||||
const float cos_theta_i = cos_from_sin(sin_theta_i);
|
||||
const float phi_i = atan2f(local_I.z, local_I.y);
|
||||
|
||||
const float phi = phi_i - phi_o;
|
||||
|
||||
float angles[6];
|
||||
hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles);
|
||||
|
||||
Spectrum F = zero_spectrum();
|
||||
float F_energy = 0.0f;
|
||||
|
||||
/* Primary specular (R), Transmission (TT) and Secondary Specular (TRT). */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const float Mp = longitudinal_scattering(angles[2 * i],
|
||||
angles[2 * i + 1],
|
||||
sin_theta_o,
|
||||
cos_theta_o,
|
||||
(i == 0) ? bsdf->m0_roughness :
|
||||
(i == 1) ? 0.25f * bsdf->v :
|
||||
4.0f * bsdf->v);
|
||||
const float Np = azimuthal_scattering(phi, i, bsdf->s, gamma_o, gamma_t);
|
||||
F += Ap[i] * Mp * Np;
|
||||
F_energy += Ap_energy[i] * Mp * Np;
|
||||
kernel_assert(isfinite_safe(F) && isfinite_safe(F_energy));
|
||||
}
|
||||
|
||||
/* Residual component (TRRT+). */
|
||||
{
|
||||
const float Mp = longitudinal_scattering(
|
||||
sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v);
|
||||
const float Np = M_1_2PI_F;
|
||||
F += Ap[3] * Mp * Np;
|
||||
F_energy += Ap_energy[3] * Mp * Np;
|
||||
kernel_assert(isfinite_safe(F) && isfinite_safe(F_energy));
|
||||
}
|
||||
|
||||
*pdf = F_energy;
|
||||
return F;
|
||||
}
|
||||
|
||||
/* Sampling function for the hair shader. */
|
||||
ccl_device int bsdf_principled_hair_sample(KernelGlobals kg,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
ccl_private ShaderData *sd,
|
||||
|
@ -413,13 +344,118 @@ ccl_device int bsdf_principled_hair_sample(KernelGlobals kg,
|
|||
ccl_private float2 *sampled_roughness,
|
||||
ccl_private float *eta)
|
||||
{
|
||||
ccl_private const PrincipledHairBSDF *bsdf = (ccl_private const PrincipledHairBSDF *)sc;
|
||||
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
|
||||
|
||||
int p = bsdf_principled_hair_impl<true>(kg, bsdf, sd, wo, eval, pdf, randu, randv);
|
||||
|
||||
*sampled_roughness = make_float2(bsdf->v_R, bsdf->v_R);
|
||||
*sampled_roughness = make_float2(bsdf->m0_roughness, bsdf->m0_roughness);
|
||||
*eta = bsdf->eta;
|
||||
|
||||
const float3 Y = float4_to_float3(bsdf->extra->geom);
|
||||
|
||||
const float3 X = safe_normalize(sd->dPdu);
|
||||
kernel_assert(fabsf(dot(X, Y)) < 1e-3f);
|
||||
const float3 Z = safe_normalize(cross(X, Y));
|
||||
|
||||
const float3 local_O = make_float3(dot(sd->wi, X), dot(sd->wi, Y), dot(sd->wi, Z));
|
||||
|
||||
float2 u[2];
|
||||
u[0] = make_float2(randu, randv);
|
||||
u[1].x = lcg_step_float(&sd->lcg_state);
|
||||
u[1].y = lcg_step_float(&sd->lcg_state);
|
||||
|
||||
const float sin_theta_o = local_O.x;
|
||||
const float cos_theta_o = cos_from_sin(sin_theta_o);
|
||||
const float phi_o = atan2f(local_O.z, local_O.y);
|
||||
|
||||
const float sin_theta_t = sin_theta_o / bsdf->eta;
|
||||
const float cos_theta_t = cos_from_sin(sin_theta_t);
|
||||
|
||||
const float sin_gamma_o = bsdf->extra->geom.w;
|
||||
const float cos_gamma_o = cos_from_sin(sin_gamma_o);
|
||||
const float gamma_o = safe_asinf(sin_gamma_o);
|
||||
|
||||
const float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o));
|
||||
const float cos_gamma_t = cos_from_sin(sin_gamma_t);
|
||||
const float gamma_t = safe_asinf(sin_gamma_t);
|
||||
|
||||
const Spectrum T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
|
||||
Spectrum Ap[4];
|
||||
float Ap_energy[4];
|
||||
hair_attenuation(
|
||||
kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap, Ap_energy);
|
||||
|
||||
int p = 0;
|
||||
for (; p < 3; p++) {
|
||||
if (u[0].x < Ap_energy[p]) {
|
||||
break;
|
||||
}
|
||||
u[0].x -= Ap_energy[p];
|
||||
}
|
||||
|
||||
float v = bsdf->v;
|
||||
if (p == 1) {
|
||||
v *= 0.25f;
|
||||
}
|
||||
if (p >= 2) {
|
||||
v *= 4.0f;
|
||||
}
|
||||
|
||||
u[1].x = max(u[1].x, 1e-5f);
|
||||
const float fac = 1.0f + v * logf(u[1].x + (1.0f - u[1].x) * expf(-2.0f / v));
|
||||
float sin_theta_i = -fac * sin_theta_o +
|
||||
cos_from_sin(fac) * cosf(M_2PI_F * u[1].y) * cos_theta_o;
|
||||
float cos_theta_i = cos_from_sin(sin_theta_i);
|
||||
|
||||
float angles[6];
|
||||
if (p < 3) {
|
||||
hair_alpha_angles(sin_theta_i, cos_theta_i, -bsdf->alpha, angles);
|
||||
sin_theta_i = angles[2 * p];
|
||||
cos_theta_i = angles[2 * p + 1];
|
||||
}
|
||||
|
||||
float phi;
|
||||
if (p < 3) {
|
||||
phi = delta_phi(p, gamma_o, gamma_t) + sample_trimmed_logistic(u[0].y, bsdf->s);
|
||||
}
|
||||
else {
|
||||
phi = M_2PI_F * u[0].y;
|
||||
}
|
||||
const float phi_i = phi_o + phi;
|
||||
|
||||
hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles);
|
||||
|
||||
Spectrum F = zero_spectrum();
|
||||
float F_energy = 0.0f;
|
||||
|
||||
/* Primary specular (R), Transmission (TT) and Secondary Specular (TRT). */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const float Mp = longitudinal_scattering(angles[2 * i],
|
||||
angles[2 * i + 1],
|
||||
sin_theta_o,
|
||||
cos_theta_o,
|
||||
(i == 0) ? bsdf->m0_roughness :
|
||||
(i == 1) ? 0.25f * bsdf->v :
|
||||
4.0f * bsdf->v);
|
||||
const float Np = azimuthal_scattering(phi, i, bsdf->s, gamma_o, gamma_t);
|
||||
F += Ap[i] * Mp * Np;
|
||||
F_energy += Ap_energy[i] * Mp * Np;
|
||||
kernel_assert(isfinite_safe(F) && isfinite_safe(F_energy));
|
||||
}
|
||||
|
||||
/* Residual component (TRRT+). */
|
||||
{
|
||||
const float Mp = longitudinal_scattering(
|
||||
sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v);
|
||||
const float Np = M_1_2PI_F;
|
||||
F += Ap[3] * Mp * Np;
|
||||
F_energy += Ap_energy[3] * Mp * Np;
|
||||
kernel_assert(isfinite_safe(F) && isfinite_safe(F_energy));
|
||||
}
|
||||
|
||||
*eval = F;
|
||||
*pdf = F_energy;
|
||||
|
||||
*wo = X * sin_theta_i + Y * cos_theta_i * cosf(phi_i) + Z * cos_theta_i * sinf(phi_i);
|
||||
|
||||
return LABEL_GLOSSY | ((p == 0) ? LABEL_REFLECT : LABEL_TRANSMIT);
|
||||
}
|
||||
|
||||
|
@ -430,30 +466,37 @@ ccl_device void bsdf_principled_hair_blur(ccl_private ShaderClosure *sc, float r
|
|||
|
||||
bsdf->v = fmaxf(roughness, bsdf->v);
|
||||
bsdf->s = fmaxf(roughness, bsdf->s);
|
||||
bsdf->v_R = fmaxf(roughness, bsdf->v_R);
|
||||
bsdf->m0_roughness = fmaxf(roughness, bsdf->m0_roughness);
|
||||
}
|
||||
|
||||
/* Hair Albedo */
|
||||
|
||||
ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(const float u_rough)
|
||||
ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
|
||||
const float azimuthal_roughness)
|
||||
{
|
||||
const float x = u_rough;
|
||||
const float x = azimuthal_roughness;
|
||||
return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f;
|
||||
}
|
||||
|
||||
ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderClosure *sc)
|
||||
ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc)
|
||||
{
|
||||
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
|
||||
/* This is simply the sum of the four Ap terms in hair_attenuation. */
|
||||
const float3 T = bsdf->extra->T;
|
||||
const float f = bsdf->extra->f;
|
||||
return safe_divide(T * (1.0f - 2.0f * f) + make_spectrum(f), one_spectrum() - f * T);
|
||||
|
||||
const float cos_theta_o = cos_from_sin(dot(sd->wi, safe_normalize(sd->dPdu)));
|
||||
const float cos_gamma_o = cos_from_sin(bsdf->extra->geom.w);
|
||||
const float f = fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta);
|
||||
|
||||
const float roughness_scale = bsdf_principled_hair_albedo_roughness_scale(bsdf->v);
|
||||
/* TODO(lukas): Adding the Fresnel term here as a workaround until the proper refactor. */
|
||||
return exp(-sqrt(bsdf->sigma) * roughness_scale) + make_spectrum(f);
|
||||
}
|
||||
|
||||
ccl_device_inline Spectrum bsdf_principled_hair_sigma_from_reflectance(const Spectrum color,
|
||||
const float u_rough)
|
||||
ccl_device_inline Spectrum
|
||||
bsdf_principled_hair_sigma_from_reflectance(const Spectrum color, const float azimuthal_roughness)
|
||||
{
|
||||
const Spectrum sigma = log(color) / bsdf_principled_hair_albedo_roughness_scale(u_rough);
|
||||
const Spectrum sigma = log(color) /
|
||||
bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness);
|
||||
return sigma * sigma;
|
||||
}
|
||||
|
||||
|
|
|
@ -1078,13 +1078,15 @@ ccl_device void osl_closure_principled_hair_setup(KernelGlobals kg,
|
|||
|
||||
bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N);
|
||||
bsdf->sigma = closure->sigma;
|
||||
bsdf->v = closure->v;
|
||||
bsdf->s = closure->s;
|
||||
bsdf->alpha = closure->alpha;
|
||||
bsdf->eta = closure->eta;
|
||||
bsdf->m0_roughness = closure->m0_roughness;
|
||||
|
||||
bsdf->extra = extra;
|
||||
|
||||
sd->flag |= bsdf_principled_hair_setup(
|
||||
sd, bsdf, closure->u_roughness, closure->coat_roughness, closure->v_roughness);
|
||||
sd->flag |= bsdf_principled_hair_setup(sd, bsdf);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -238,9 +238,9 @@ OSL_CLOSURE_STRUCT_END(HairTransmission, hair_transmission)
|
|||
OSL_CLOSURE_STRUCT_BEGIN(PrincipledHair, principled_hair)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, VECTOR, packed_float3, N, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, VECTOR, packed_float3, sigma, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, u_roughness, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, v_roughness, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, coat_roughness, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, v, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, s, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, m0_roughness, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, alpha, NULL)
|
||||
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, eta, NULL)
|
||||
OSL_CLOSURE_STRUCT_END(PrincipledHair, principled_hair)
|
||||
|
|
|
@ -53,7 +53,7 @@ shader node_principled_hair_bsdf(color Color = color(0.017513, 0.005763, 0.00205
|
|||
|
||||
/* Compute roughness. */
|
||||
float factor_random_roughness = 1.0 + 2.0 * (random_value - 0.5) * RandomRoughness;
|
||||
float coat_roughness = 1.0 - clamp(Coat, 0.0, 1.0);
|
||||
float m0_roughness = 1.0 - clamp(Coat, 0.0, 1.0);
|
||||
float roughness = Roughness * factor_random_roughness;
|
||||
float radial_roughness = RadialRoughness * factor_random_roughness;
|
||||
|
||||
|
@ -88,5 +88,5 @@ shader node_principled_hair_bsdf(color Color = color(0.017513, 0.005763, 0.00205
|
|||
sigma = sigma_from_concentration(0.0, 0.8054375);
|
||||
}
|
||||
|
||||
BSDF = principled_hair(Normal, sigma, roughness, radial_roughness, coat_roughness, Offset, IOR);
|
||||
BSDF = principled_hair(Normal, sigma, roughness, radial_roughness, m0_roughness, Offset, IOR);
|
||||
}
|
||||
|
|
|
@ -802,9 +802,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
|
||||
/* Remap Coat value to [0, 100]% of Roughness. */
|
||||
float coat = stack_load_float_default(stack, coat_ofs, data_node2.y);
|
||||
float coat_roughness = 1.0f - clamp(coat, 0.0f, 1.0f);
|
||||
float m0_roughness = 1.0f - clamp(coat, 0.0f, 1.0f);
|
||||
|
||||
bsdf->N = N;
|
||||
bsdf->v = roughness;
|
||||
bsdf->s = radial_roughness;
|
||||
bsdf->m0_roughness = m0_roughness;
|
||||
bsdf->alpha = alpha;
|
||||
bsdf->eta = ior;
|
||||
bsdf->extra = extra;
|
||||
|
@ -857,8 +860,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
|
|||
}
|
||||
}
|
||||
|
||||
sd->flag |= bsdf_principled_hair_setup(
|
||||
sd, bsdf, roughness, coat_roughness, radial_roughness);
|
||||
sd->flag |= bsdf_principled_hair_setup(sd, bsdf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -306,14 +306,23 @@ static void gwl_window_frame_update_from_pending(GWL_Window *win);
|
|||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
|
||||
enum eGWL_PendingWindowActions {
|
||||
PENDING_FRAME_CONFIGURE = 0,
|
||||
PENDING_EGL_RESIZE,
|
||||
/**
|
||||
* The state of the window frame has changed, apply the state from #GWL_Window::frame_pending.
|
||||
*/
|
||||
PENDING_WINDOW_FRAME_CONFIGURE = 0,
|
||||
/** The EGL buffer must be resized to match #GWL_WindowFrame::size. */
|
||||
PENDING_EGL_WINDOW_RESIZE,
|
||||
# ifdef GHOST_OPENGL_ALPHA
|
||||
/** Draw an opaque region behind the window. */
|
||||
PENDING_OPAQUE_SET,
|
||||
# endif
|
||||
PENDING_SCALE_UPDATE,
|
||||
/**
|
||||
* The DPI for a monitor has changed or the monitors (outputs)
|
||||
* this window is visible on may have changed. Recalculate the windows scale.
|
||||
*/
|
||||
PENDING_OUTPUT_SCALE_UPDATE,
|
||||
};
|
||||
# define PENDING_NUM (PENDING_SCALE_UPDATE + 1)
|
||||
# define PENDING_NUM (PENDING_OUTPUT_SCALE_UPDATE + 1)
|
||||
|
||||
static void gwl_window_pending_actions_tag(GWL_Window *win, enum eGWL_PendingWindowActions type)
|
||||
{
|
||||
|
@ -323,10 +332,10 @@ static void gwl_window_pending_actions_tag(GWL_Window *win, enum eGWL_PendingWin
|
|||
|
||||
static void gwl_window_pending_actions_handle(GWL_Window *win)
|
||||
{
|
||||
if (win->pending_actions[PENDING_FRAME_CONFIGURE].exchange(false)) {
|
||||
if (win->pending_actions[PENDING_WINDOW_FRAME_CONFIGURE].exchange(false)) {
|
||||
gwl_window_frame_update_from_pending(win);
|
||||
}
|
||||
if (win->pending_actions[PENDING_EGL_RESIZE].exchange(false)) {
|
||||
if (win->pending_actions[PENDING_EGL_WINDOW_RESIZE].exchange(false)) {
|
||||
wl_egl_window_resize(win->egl_window, UNPACK2(win->frame.size), 0, 0);
|
||||
}
|
||||
# ifdef GHOST_OPENGL_ALPHA
|
||||
|
@ -334,7 +343,7 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
|
|||
win->ghost_window->setOpaque();
|
||||
}
|
||||
# endif
|
||||
if (win->pending_actions[PENDING_SCALE_UPDATE].exchange(false)) {
|
||||
if (win->pending_actions[PENDING_OUTPUT_SCALE_UPDATE].exchange(false)) {
|
||||
win->ghost_window->outputs_changed_update_scale();
|
||||
}
|
||||
}
|
||||
|
@ -342,9 +351,10 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
|
|||
#endif /* USE_EVENT_BACKGROUND_THREAD */
|
||||
|
||||
/**
|
||||
* Update the window's #GWL_WindowFrame
|
||||
* Update the window's #GWL_WindowFrame.
|
||||
* The caller must handle locking & run from the main thread.
|
||||
*/
|
||||
static void gwl_window_frame_update_from_pending_lockfree(GWL_Window *win)
|
||||
static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
|
||||
{
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
GHOST_ASSERT(win->ghost_system->main_thread_id == std::this_thread::get_id(),
|
||||
|
@ -381,7 +391,7 @@ static void gwl_window_frame_update_from_pending(GWL_Window *win)
|
|||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
std::lock_guard lock_frame_guard{win->frame_pending_mutex};
|
||||
#endif
|
||||
gwl_window_frame_update_from_pending_lockfree(win);
|
||||
gwl_window_frame_update_from_pending_no_lock(win);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -576,12 +586,12 @@ static void frame_handle_configure(struct libdecor_frame *frame,
|
|||
GHOST_SystemWayland *system = win->ghost_system;
|
||||
const bool is_main_thread = system->main_thread_id == std::this_thread::get_id();
|
||||
if (!is_main_thread) {
|
||||
gwl_window_pending_actions_tag(win, PENDING_FRAME_CONFIGURE);
|
||||
gwl_window_pending_actions_tag(win, PENDING_WINDOW_FRAME_CONFIGURE);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
gwl_window_frame_update_from_pending_lockfree(win);
|
||||
gwl_window_frame_update_from_pending_no_lock(win);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -671,7 +681,7 @@ static void xdg_surface_handle_configure(void *data,
|
|||
if (!is_main_thread) {
|
||||
/* NOTE(@ideasman42): this only gets one redraw,
|
||||
* I could not find a case where this causes problems. */
|
||||
gwl_window_pending_actions_tag(win, PENDING_FRAME_CONFIGURE);
|
||||
gwl_window_pending_actions_tag(win, PENDING_WINDOW_FRAME_CONFIGURE);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -1373,7 +1383,7 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
|
|||
{
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
if (system_->main_thread_id != std::this_thread::get_id()) {
|
||||
gwl_window_pending_actions_tag(window_, PENDING_SCALE_UPDATE);
|
||||
gwl_window_pending_actions_tag(window_, PENDING_OUTPUT_SCALE_UPDATE);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -93,7 +93,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
|||
}
|
||||
|
||||
RECT win_rect = {left, top, long(left + width), long(top + height)};
|
||||
adjustWindowRectForClosestMonitor(&win_rect, style, extended_style);
|
||||
adjustWindowRectForDesktop(&win_rect, style, extended_style);
|
||||
|
||||
wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
|
||||
m_hWnd = ::CreateWindowExW(extended_style, /* window extended style */
|
||||
|
@ -298,24 +298,52 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
|
|||
m_directManipulationHelper = NULL;
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
|
||||
DWORD dwStyle,
|
||||
DWORD dwExStyle)
|
||||
void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle)
|
||||
{
|
||||
/* Get Details of the closest monitor. */
|
||||
HMONITOR hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
|
||||
/* Windows can span multiple monitors, but must be usable. The desktop can have a larger
|
||||
* surface than all monitors combined, for example when two monitors are aligned diagonally.
|
||||
* Therefore we ensure that all the window's corners are within some monitor's Work area. */
|
||||
|
||||
POINT pt;
|
||||
HMONITOR hmonitor;
|
||||
MONITORINFOEX monitor;
|
||||
monitor.cbSize = sizeof(MONITORINFOEX);
|
||||
monitor.dwFlags = 0;
|
||||
GetMonitorInfo(hmonitor, &monitor);
|
||||
|
||||
/* Constrain requested size and position to fit within this monitor. */
|
||||
LONG width = min(monitor.rcWork.right - monitor.rcWork.left, win_rect->right - win_rect->left);
|
||||
LONG height = min(monitor.rcWork.bottom - monitor.rcWork.top, win_rect->bottom - win_rect->top);
|
||||
win_rect->left = min(max(monitor.rcWork.left, win_rect->left), monitor.rcWork.right - width);
|
||||
win_rect->right = win_rect->left + width;
|
||||
win_rect->top = min(max(monitor.rcWork.top, win_rect->top), monitor.rcWork.bottom - height);
|
||||
win_rect->bottom = win_rect->top + height;
|
||||
/* Note that with MonitorFromPoint using MONITOR_DEFAULTTONEAREST, it will return
|
||||
* the exact monitor if there is one at the location or the nearest monitor if not. */
|
||||
|
||||
/* Top-left. */
|
||||
pt.x = win_rect->left;
|
||||
pt.y = win_rect->top;
|
||||
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
|
||||
GetMonitorInfo(hmonitor, &monitor);
|
||||
win_rect->top = max(win_rect->top, monitor.rcWork.top);
|
||||
win_rect->left = max(win_rect->left, monitor.rcWork.left);
|
||||
|
||||
/* Top-right. */
|
||||
pt.x = win_rect->right;
|
||||
pt.y = win_rect->top;
|
||||
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
|
||||
GetMonitorInfo(hmonitor, &monitor);
|
||||
win_rect->top = max(win_rect->top, monitor.rcWork.top);
|
||||
win_rect->right = min(win_rect->right, monitor.rcWork.right);
|
||||
|
||||
/* Bottom-left. */
|
||||
pt.x = win_rect->left;
|
||||
pt.y = win_rect->bottom;
|
||||
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
|
||||
GetMonitorInfo(hmonitor, &monitor);
|
||||
win_rect->bottom = min(win_rect->bottom, monitor.rcWork.bottom);
|
||||
win_rect->left = max(win_rect->left, monitor.rcWork.left);
|
||||
|
||||
/* Bottom-right. */
|
||||
pt.x = win_rect->right;
|
||||
pt.y = win_rect->bottom;
|
||||
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
|
||||
GetMonitorInfo(hmonitor, &monitor);
|
||||
win_rect->bottom = min(win_rect->bottom, monitor.rcWork.bottom);
|
||||
win_rect->right = min(win_rect->right, monitor.rcWork.right);
|
||||
|
||||
/* With Windows 10 and newer we can adjust for chrome that differs with DPI and scale. */
|
||||
GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr;
|
||||
|
@ -334,9 +362,6 @@ void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
|
|||
else {
|
||||
AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle);
|
||||
}
|
||||
|
||||
/* But never allow a top position that can hide part of the title bar. */
|
||||
win_rect->top = max(monitor.rcWork.top, win_rect->top);
|
||||
}
|
||||
|
||||
bool GHOST_WindowWin32::getValid() const
|
||||
|
|
|
@ -87,12 +87,12 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
|||
~GHOST_WindowWin32();
|
||||
|
||||
/**
|
||||
* Adjusts a requested window rect to fit and position correctly in monitor.
|
||||
* Adjusts a requested window rect to fit and position within the desktop.
|
||||
* \param win_rect: pointer to rectangle that will be modified.
|
||||
* \param dwStyle: The Window Style of the window whose required size is to be calculated.
|
||||
* \param dwExStyle: The Extended Window Style of the window.
|
||||
*/
|
||||
void adjustWindowRectForClosestMonitor(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle);
|
||||
void adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle);
|
||||
|
||||
/**
|
||||
* Returns indication as to whether the window is valid.
|
||||
|
|
|
@ -281,6 +281,8 @@ inline T *MEM_new(const char *allocation_name, Args &&...args)
|
|||
*/
|
||||
template<typename T> inline void MEM_delete(const T *ptr)
|
||||
{
|
||||
static_assert(!std::is_void_v<T>,
|
||||
"MEM_delete on a void pointer not possible. Cast it to a non-void type?");
|
||||
if (ptr == nullptr) {
|
||||
/* Support #ptr being null, because C++ `delete` supports that as well. */
|
||||
return;
|
||||
|
|
|
@ -991,6 +991,7 @@ url_manual_mapping = (
|
|||
("bpy.types.geometrynodeinputmeshfacearea*", "modeling/geometry_nodes/mesh/read/face_area.html#bpy-types-geometrynodeinputmeshfacearea"),
|
||||
("bpy.types.geometrynodeinputsplinecyclic*", "modeling/geometry_nodes/curve/read/is_spline_cyclic.html#bpy-types-geometrynodeinputsplinecyclic"),
|
||||
("bpy.types.geometrynodeinstancestopoints*", "modeling/geometry_nodes/instances/instances_to_points.html#bpy-types-geometrynodeinstancestopoints"),
|
||||
("bpy.types.geometrynodematerialselection*", "modeling/geometry_nodes/material/material_selection.html#bpy-types-geometrynodematerialselection"),
|
||||
("bpy.types.gpencillayer.viewlayer_render*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-viewlayer-render"),
|
||||
("bpy.types.imagepaint.use_normal_falloff*", "sculpt_paint/brush/falloff.html#bpy-types-imagepaint-use-normal-falloff"),
|
||||
("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"),
|
||||
|
@ -2027,6 +2028,7 @@ url_manual_mapping = (
|
|||
("bpy.ops.graph.equalize_handles*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-equalize-handles"),
|
||||
("bpy.ops.mball.delete_metaelems*", "modeling/metas/editing.html#bpy-ops-mball-delete-metaelems"),
|
||||
("bpy.ops.mball.reveal_metaelems*", "modeling/metas/properties.html#bpy-ops-mball-reveal-metaelems"),
|
||||
("bpy.ops.mesh.bridge_edge_loops*", "modeling/meshes/editing/edge/bridge_edge_loops.html#bpy-ops-mesh-bridge-edge-loops"),
|
||||
("bpy.ops.mesh.intersect_boolean*", "modeling/meshes/editing/face/intersect_boolean.html#bpy-ops-mesh-intersect-boolean"),
|
||||
("bpy.ops.mesh.loop_multi_select*", "modeling/meshes/selecting/loops.html#bpy-ops-mesh-loop-multi-select"),
|
||||
("bpy.ops.mesh.vert_connect_path*", "modeling/meshes/editing/vertex/connect_vertex_path.html#bpy-ops-mesh-vert-connect-path"),
|
||||
|
@ -3021,6 +3023,7 @@ url_manual_mapping = (
|
|||
("bpy.types.bakesettings*", "render/cycles/baking.html#bpy-types-bakesettings"),
|
||||
("bpy.types.blendtexture*", "render/materials/legacy_textures/types/blend.html#bpy-types-blendtexture"),
|
||||
("bpy.types.brush.height*", "sculpt_paint/sculpting/tools/layer.html#bpy-types-brush-height"),
|
||||
("bpy.types.brush.jitter*", "sculpt_paint/brush/stroke.html#bpy-types-brush-jitter"),
|
||||
("bpy.types.castmodifier*", "modeling/modifiers/deform/cast.html#bpy-types-castmodifier"),
|
||||
("bpy.types.curve.offset*", "modeling/curves/properties/geometry.html#bpy-types-curve-offset"),
|
||||
("bpy.types.geometrynode*", "modeling/geometry_nodes/index.html#bpy-types-geometrynode"),
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
icon_modifier="#84b8ffff"
|
||||
icon_shading="#ea7581ff"
|
||||
icon_folder="#e3c16eff"
|
||||
icon_border_intensity="0.85"
|
||||
icon_border_intensity="1"
|
||||
>
|
||||
<wcol_regular>
|
||||
<ThemeWidgetColors
|
||||
outline="#b8b8b8"
|
||||
outline="#4d4d4d"
|
||||
inner="#dbdbdbff"
|
||||
inner_sel="#668cccff"
|
||||
item="#191919ff"
|
||||
|
@ -48,7 +48,7 @@
|
|||
</wcol_regular>
|
||||
<wcol_tool>
|
||||
<ThemeWidgetColors
|
||||
outline="#b8b8b8"
|
||||
outline="#4d4d4d"
|
||||
inner="#dbdbdbff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#191919ff"
|
||||
|
@ -63,7 +63,7 @@
|
|||
</wcol_tool>
|
||||
<wcol_toolbar_item>
|
||||
<ThemeWidgetColors
|
||||
outline="#363636"
|
||||
outline="#4d4d4d"
|
||||
inner="#434343ff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#e6e6e6cc"
|
||||
|
@ -78,7 +78,7 @@
|
|||
</wcol_toolbar_item>
|
||||
<wcol_radio>
|
||||
<ThemeWidgetColors
|
||||
outline="#434343"
|
||||
outline="#4d4d4d"
|
||||
inner="#3b3b3bff"
|
||||
inner_sel="#5680c2e6"
|
||||
item="#ffffffff"
|
||||
|
@ -93,7 +93,7 @@
|
|||
</wcol_radio>
|
||||
<wcol_text>
|
||||
<ThemeWidgetColors
|
||||
outline="#666666"
|
||||
outline="#4d4d4d"
|
||||
inner="#282828ff"
|
||||
inner_sel="#333333ff"
|
||||
item="#5680c2ff"
|
||||
|
@ -108,7 +108,7 @@
|
|||
</wcol_text>
|
||||
<wcol_option>
|
||||
<ThemeWidgetColors
|
||||
outline="#373737"
|
||||
outline="#4d4d4d"
|
||||
inner="#3c3c3cff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#ffffffff"
|
||||
|
@ -123,8 +123,8 @@
|
|||
</wcol_option>
|
||||
<wcol_toggle>
|
||||
<ThemeWidgetColors
|
||||
outline="#999999"
|
||||
inner="#c0c0c0ff"
|
||||
outline="#4d4d4d"
|
||||
inner="#dbdbdbff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#191919ff"
|
||||
text="#000000"
|
||||
|
@ -138,7 +138,7 @@
|
|||
</wcol_toggle>
|
||||
<wcol_num>
|
||||
<ThemeWidgetColors
|
||||
outline="#b8b8b8"
|
||||
outline="#4d4d4d"
|
||||
inner="#d3d3d3ff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#80b1ffff"
|
||||
|
@ -153,7 +153,7 @@
|
|||
</wcol_num>
|
||||
<wcol_numslider>
|
||||
<ThemeWidgetColors
|
||||
outline="#b8b8b8"
|
||||
outline="#4d4d4d"
|
||||
inner="#999999ff"
|
||||
inner_sel="#999999ff"
|
||||
item="#e6e6e6ff"
|
||||
|
@ -168,8 +168,8 @@
|
|||
</wcol_numslider>
|
||||
<wcol_box>
|
||||
<ThemeWidgetColors
|
||||
outline="#959595"
|
||||
inner="#cccccc80"
|
||||
outline="#4d4d4d"
|
||||
inner="#80808080"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#191919ff"
|
||||
text="#333333"
|
||||
|
@ -183,7 +183,7 @@
|
|||
</wcol_box>
|
||||
<wcol_menu>
|
||||
<ThemeWidgetColors
|
||||
outline="#3b3b3b"
|
||||
outline="#3d3d3d"
|
||||
inner="#3b3b3bff"
|
||||
inner_sel="#767676ff"
|
||||
item="#808080ff"
|
||||
|
@ -217,7 +217,7 @@
|
|||
inner="#c0c0c0ff"
|
||||
inner_sel="#cdcdcdff"
|
||||
item="#727272ff"
|
||||
text="#1a1a1a"
|
||||
text="#4d4d4d"
|
||||
text_sel="#1a1a1a"
|
||||
show_shaded="FALSE"
|
||||
shadetop="25"
|
||||
|
@ -304,11 +304,11 @@
|
|||
<wcol_list_item>
|
||||
<ThemeWidgetColors
|
||||
outline="#e6e6e6"
|
||||
inner="#00000000"
|
||||
inner_sel="#808080ff"
|
||||
inner="#1a1a1a00"
|
||||
inner_sel="#c0c0c0ff"
|
||||
item="#1a1a1aff"
|
||||
text="#1a1a1a"
|
||||
text_sel="#ffffff"
|
||||
text_sel="#000000"
|
||||
show_shaded="FALSE"
|
||||
shadetop="0"
|
||||
shadedown="0"
|
||||
|
@ -316,6 +316,21 @@
|
|||
>
|
||||
</ThemeWidgetColors>
|
||||
</wcol_list_item>
|
||||
<wcol_view_item>
|
||||
<ThemeWidgetColors
|
||||
outline="#e6e6e6"
|
||||
inner="#c0c0c044"
|
||||
inner_sel="#c0c0c0ff"
|
||||
item="#1a1a1aff"
|
||||
text="#1a1a1a"
|
||||
text_sel="#000000"
|
||||
show_shaded="FALSE"
|
||||
shadetop="0"
|
||||
shadedown="0"
|
||||
roundness="0.4"
|
||||
>
|
||||
</ThemeWidgetColors>
|
||||
</wcol_view_item>
|
||||
<wcol_state>
|
||||
<ThemeWidgetStateColors
|
||||
inner_anim="#73be4c"
|
||||
|
@ -334,8 +349,8 @@
|
|||
</wcol_state>
|
||||
<wcol_tab>
|
||||
<ThemeWidgetColors
|
||||
outline="#656565"
|
||||
inner="#818181ff"
|
||||
outline="#333333"
|
||||
inner="#808080cc"
|
||||
inner_sel="#b3b3b3ff"
|
||||
item="#28292dff"
|
||||
text="#1a1a1a"
|
||||
|
@ -414,6 +429,7 @@
|
|||
bone_locked_weight="#ff000080"
|
||||
bundle_solid="#c8c8c8"
|
||||
camera_path="#000000"
|
||||
camera_passepartout="#000000"
|
||||
skin_root="#b44d4d"
|
||||
view_overlay="#000000"
|
||||
transform="#ffffff"
|
||||
|
@ -452,9 +468,9 @@
|
|||
</gradients>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b3ff"
|
||||
back="#b3b3b3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -519,9 +535,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -552,7 +568,7 @@
|
|||
header="#adadadff"
|
||||
header_text="#000000"
|
||||
header_text_hi="#ffffff"
|
||||
button="#999999e6"
|
||||
button="#b3b3b3ff"
|
||||
button_title="#1a1a1a"
|
||||
button_text="#000000"
|
||||
button_text_hi="#000000"
|
||||
|
@ -565,9 +581,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -623,9 +639,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -698,9 +714,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -783,9 +799,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b3ff"
|
||||
back="#b3b3b3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -843,14 +859,23 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b3ff"
|
||||
back="#b3b3b3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
</ThemeSpaceGeneric>
|
||||
</space>
|
||||
<space_list>
|
||||
<ThemeSpaceListGeneric
|
||||
list="#181818"
|
||||
list_title="#ffffff"
|
||||
list_text="#ffffff"
|
||||
list_text_hi="#ffffff"
|
||||
>
|
||||
</ThemeSpaceListGeneric>
|
||||
</space_list>
|
||||
</ThemeSequenceEditor>
|
||||
</sequence_editor>
|
||||
<properties>
|
||||
|
@ -871,7 +896,7 @@
|
|||
button_title="#000000"
|
||||
button_text="#000000"
|
||||
button_text_hi="#000000"
|
||||
navigation_bar="#656565ff"
|
||||
navigation_bar="#1d1d1dff"
|
||||
execution_buts="#00000000"
|
||||
tab_active="#6697e6"
|
||||
tab_inactive="#535353"
|
||||
|
@ -880,9 +905,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b300"
|
||||
back="#a3a3a3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -927,9 +952,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -939,44 +964,44 @@
|
|||
</text_editor>
|
||||
<node_editor>
|
||||
<ThemeNodeEditor
|
||||
grid="#1B1B1B"
|
||||
node_selected="#f15800"
|
||||
node_active="#f15800"
|
||||
wire="#191919"
|
||||
wire_inner="#999999"
|
||||
wire_select="#ffa733"
|
||||
selected_text="#7f7070"
|
||||
node_backdrop="#e6e6e6ff"
|
||||
converter_node="#66c4ff"
|
||||
color_node="#ffcb4d"
|
||||
group_node="#59b36ab9"
|
||||
group_socket_node="#dfc300"
|
||||
frame_node="#9b9b9b60"
|
||||
matte_node="#977474"
|
||||
distor_node="#749797"
|
||||
grid="#282828"
|
||||
node_selected="#ed5700"
|
||||
node_active="#ffffff"
|
||||
wire="#1a1a1aff"
|
||||
wire_inner="#8d8d8d"
|
||||
wire_select="#ffffffb3"
|
||||
selected_text="#7f7f7f"
|
||||
node_backdrop="#666666ff"
|
||||
converter_node="#12adff"
|
||||
color_node="#cccc00"
|
||||
group_node="#3b660a"
|
||||
group_socket_node="#000000"
|
||||
frame_node="#0f0f0fcc"
|
||||
matte_node="#973c3c"
|
||||
distor_node="#4c9797"
|
||||
noodle_curving="4"
|
||||
grid_levels="3"
|
||||
dash_alpha="0.5"
|
||||
input_node="#cb3d4a"
|
||||
output_node="#cb3d4a"
|
||||
filter_node="#6c696f"
|
||||
vector_node="#9999ff"
|
||||
texture_node="#ffc399"
|
||||
shader_node="#ea7581"
|
||||
script_node="#6c696f"
|
||||
input_node="#ff3371"
|
||||
output_node="#4d0017"
|
||||
filter_node="#551a80"
|
||||
vector_node="#4d4dff"
|
||||
texture_node="#e66800"
|
||||
shader_node="#24b524"
|
||||
script_node="#084d4d"
|
||||
pattern_node="#6c696f"
|
||||
layout_node="#6c696f"
|
||||
geometry_node="#00d7a4"
|
||||
attribute_node="#3f5980"
|
||||
geometry_node="#00d6a3"
|
||||
attribute_node="#001566"
|
||||
>
|
||||
<space>
|
||||
<ThemeSpaceGeneric
|
||||
back="#353535"
|
||||
title="#000000"
|
||||
text="#000000"
|
||||
back="#1d1d1d"
|
||||
title="#eeeeee"
|
||||
text="#e6e6e6"
|
||||
text_hi="#ffffff"
|
||||
header="#b3b3b3ff"
|
||||
header_text="#000000"
|
||||
header_text="#eeeeee"
|
||||
header_text_hi="#ffffff"
|
||||
button="#99999900"
|
||||
button_title="#1a1a1a"
|
||||
|
@ -991,9 +1016,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b3ff"
|
||||
back="#b3b3b3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1013,8 +1038,8 @@
|
|||
<outliner>
|
||||
<ThemeOutliner
|
||||
match="#337f33"
|
||||
selected_highlight="#7a8e99"
|
||||
active="#92aab7"
|
||||
selected_highlight="#7a8499"
|
||||
active="#929eb7"
|
||||
selected_object="#ffddb3"
|
||||
active_object="#ffffff"
|
||||
edited_object="#0080624d"
|
||||
|
@ -1042,9 +1067,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1091,9 +1116,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1125,9 +1150,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b300"
|
||||
back="#a3a3a3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1137,26 +1162,26 @@
|
|||
</preferences>
|
||||
<console>
|
||||
<ThemeConsole
|
||||
line_output="#6080ff"
|
||||
line_input="#ffffff"
|
||||
line_info="#00aa00"
|
||||
line_error="#dc6060"
|
||||
cursor="#dc6060"
|
||||
line_output="#71a8ff"
|
||||
line_input="#f2f2f2"
|
||||
line_info="#95d600"
|
||||
line_error="#ff4d84"
|
||||
cursor="#ff0000"
|
||||
select="#ffffff30"
|
||||
>
|
||||
<space>
|
||||
<ThemeSpaceGeneric
|
||||
back="#000000"
|
||||
title="#000000"
|
||||
text="#000000"
|
||||
back="#1d1d1d"
|
||||
title="#eeeeee"
|
||||
text="#e6e6e6"
|
||||
text_hi="#ffffff"
|
||||
header="#b3b3b3ff"
|
||||
header_text="#000000"
|
||||
header_text_hi="#ffffff"
|
||||
button="#7272727f"
|
||||
button_title="#000000"
|
||||
button_text="#000000"
|
||||
button_text_hi="#000000"
|
||||
button="#30303000"
|
||||
button_title="#ffffff"
|
||||
button_text="#cccccc"
|
||||
button_text_hi="#ffffff"
|
||||
navigation_bar="#00000000"
|
||||
execution_buts="#00000000"
|
||||
tab_active="#6697e6"
|
||||
|
@ -1166,9 +1191,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1231,9 +1256,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1274,9 +1299,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1292,7 +1317,7 @@
|
|||
title="#ffffff"
|
||||
text="#ffffff"
|
||||
text_hi="#ffffff"
|
||||
header="#adadadff"
|
||||
header="#999999ff"
|
||||
header_text="#1a1a1a"
|
||||
header_text_hi="#ffffff"
|
||||
button="#2f303500"
|
||||
|
@ -1308,9 +1333,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1331,7 +1356,7 @@
|
|||
header="#adadadff"
|
||||
header_text="#000000"
|
||||
header_text_hi="#ffffff"
|
||||
button="#999999e6"
|
||||
button="#b3b3b3ff"
|
||||
button_title="#1a1a1a"
|
||||
button_text="#000000"
|
||||
button_text_hi="#000000"
|
||||
|
@ -1344,9 +1369,9 @@
|
|||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
|
@ -1585,8 +1610,8 @@
|
|||
shadow="3"
|
||||
shadow_offset_x="0"
|
||||
shadow_offset_y="-1"
|
||||
shadow_alpha="0.3"
|
||||
shadow_value="0.7"
|
||||
shadow_alpha="1"
|
||||
shadow_value="0.8"
|
||||
>
|
||||
</ThemeFontStyle>
|
||||
</panel_title>
|
||||
|
@ -1596,8 +1621,8 @@
|
|||
shadow="3"
|
||||
shadow_offset_x="0"
|
||||
shadow_offset_y="-1"
|
||||
shadow_alpha="0.3"
|
||||
shadow_value="0.7"
|
||||
shadow_alpha="0"
|
||||
shadow_value="0.8"
|
||||
>
|
||||
</ThemeFontStyle>
|
||||
</widget_label>
|
||||
|
@ -1607,8 +1632,8 @@
|
|||
shadow="1"
|
||||
shadow_offset_x="0"
|
||||
shadow_offset_y="-1"
|
||||
shadow_alpha="0.3"
|
||||
shadow_value="0.7"
|
||||
shadow_alpha="0"
|
||||
shadow_value="0.8"
|
||||
>
|
||||
</ThemeFontStyle>
|
||||
</widget>
|
||||
|
|
|
@ -5629,6 +5629,10 @@ def km_curves(params):
|
|||
("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None),
|
||||
*_template_items_select_actions(params, "curves.select_all"),
|
||||
("curves.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||
("curves.delete", {"type": 'X', "value": 'PRESS'}, None),
|
||||
("curves.delete", {"type": 'DEL', "value": 'PRESS'}, None),
|
||||
("curves.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||
("curves.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -6345,9 +6349,8 @@ def km_node_link_modal_map(_params):
|
|||
|
||||
return keymap
|
||||
|
||||
|
||||
# Fallback for gizmos that don't have custom a custom key-map.
|
||||
|
||||
|
||||
def km_generic_gizmo(_params):
|
||||
keymap = (
|
||||
"Generic Gizmo",
|
||||
|
|
|
@ -6,8 +6,8 @@ from bpy.types import Operator
|
|||
from bpy.app.translations import pgettext_data as data_
|
||||
|
||||
|
||||
def geometry_node_group_empty_new():
|
||||
group = bpy.data.node_groups.new(data_("Geometry Nodes"), 'GeometryNodeTree')
|
||||
def build_default_empty_geometry_node_group(name):
|
||||
group = bpy.data.node_groups.new(name, 'GeometryNodeTree')
|
||||
group.inputs.new('NodeSocketGeometry', data_("Geometry"))
|
||||
group.outputs.new('NodeSocketGeometry', data_("Geometry"))
|
||||
input_node = group.nodes.new('NodeGroupInput')
|
||||
|
@ -20,8 +20,12 @@ def geometry_node_group_empty_new():
|
|||
input_node.location.x = -200 - input_node.width
|
||||
output_node.location.x = 200
|
||||
|
||||
group.links.new(output_node.inputs[0], input_node.outputs[0])
|
||||
return group
|
||||
|
||||
|
||||
def geometry_node_group_empty_new():
|
||||
group = build_default_empty_geometry_node_group(data_("Geometry Nodes"))
|
||||
group.links.new(group.nodes["Group Input"].outputs[0], group.nodes["Group Output"].inputs[0])
|
||||
return group
|
||||
|
||||
|
||||
|
@ -35,6 +39,158 @@ def geometry_modifier_poll(context):
|
|||
return True
|
||||
|
||||
|
||||
def get_context_modifier(context):
|
||||
if context.area.type == 'PROPERTIES':
|
||||
modifier = context.modifier
|
||||
else:
|
||||
modifier = context.object.modifiers.active
|
||||
if modifier is None or modifier.type != 'NODES':
|
||||
return None
|
||||
return modifier
|
||||
|
||||
|
||||
def edit_geometry_nodes_modifier_poll(context):
|
||||
return get_context_modifier(context) is not None
|
||||
|
||||
|
||||
def socket_idname_to_attribute_type(idname):
|
||||
if idname.startswith("NodeSocketInt"):
|
||||
return "INT"
|
||||
elif idname.startswith("NodeSocketColor"):
|
||||
return "FLOAT_COLOR"
|
||||
elif idname.startswith("NodeSocketVector"):
|
||||
return "FLOAT_VECTOR"
|
||||
elif idname.startswith("NodeSocketBool"):
|
||||
return "BOOLEAN"
|
||||
elif idname.startswith("NodeSocketFloat"):
|
||||
return "FLOAT"
|
||||
raise ValueError("Unsupported socket type")
|
||||
return ""
|
||||
|
||||
|
||||
def modifier_attribute_name_get(modifier, identifier):
|
||||
try:
|
||||
return modifier[identifier + "_attribute_name"]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
def modifier_input_use_attribute(modifier, identifier):
|
||||
try:
|
||||
return modifier[identifier + "_use_attribute"] != 0
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
def get_socket_with_identifier(sockets, identifier):
|
||||
for socket in sockets:
|
||||
if socket.identifier == identifier:
|
||||
return socket
|
||||
return None
|
||||
|
||||
|
||||
def get_enabled_socket_with_name(sockets, name):
|
||||
for socket in sockets:
|
||||
if socket.name == name and socket.enabled:
|
||||
return socket
|
||||
return None
|
||||
|
||||
|
||||
class MoveModifierToNodes(Operator):
|
||||
"""Move inputs and outputs from in the modifier to a new node group"""
|
||||
|
||||
bl_idname = "object.geometry_nodes_move_to_nodes"
|
||||
bl_label = "Move to Nodes"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return edit_geometry_nodes_modifier_poll(context)
|
||||
|
||||
def execute(self, context):
|
||||
modifier = get_context_modifier(context)
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
old_group = modifier.node_group
|
||||
if not old_group:
|
||||
return {'CANCELLED'}
|
||||
|
||||
wrapper_name = old_group.name + ".wrapper"
|
||||
group = build_default_empty_geometry_node_group(wrapper_name)
|
||||
group_node = group.nodes.new("GeometryNodeGroup")
|
||||
group_node.node_tree = old_group
|
||||
group_node.update()
|
||||
|
||||
group_input_node = group.nodes["Group Input"]
|
||||
group_output_node = group.nodes["Group Output"]
|
||||
|
||||
# Copy default values for inputs and create named attribute input nodes.
|
||||
input_nodes = []
|
||||
first_geometry_input = None
|
||||
for input_socket in old_group.inputs:
|
||||
identifier = input_socket.identifier
|
||||
group_node_input = get_socket_with_identifier(group_node.inputs, identifier)
|
||||
if modifier_input_use_attribute(modifier, identifier):
|
||||
input_node = group.nodes.new("GeometryNodeInputNamedAttribute")
|
||||
input_nodes.append(input_node)
|
||||
input_node.data_type = socket_idname_to_attribute_type(input_socket.bl_socket_idname)
|
||||
attribute_name = modifier_attribute_name_get(modifier, identifier)
|
||||
input_node.inputs["Name"].default_value = attribute_name
|
||||
output_socket = get_enabled_socket_with_name(input_node.outputs, "Attribute")
|
||||
group.links.new(output_socket, group_node_input)
|
||||
elif hasattr(input_socket, "default_value"):
|
||||
group_node_input.default_value = modifier[identifier]
|
||||
elif input_socket.bl_socket_idname == 'NodeSocketGeometry':
|
||||
if not first_geometry_input:
|
||||
first_geometry_input = group_node_input
|
||||
|
||||
group.links.new(group_input_node.outputs[0], first_geometry_input)
|
||||
|
||||
# Adjust locations of named attribute input nodes and group input node to make some space.
|
||||
if input_nodes:
|
||||
for i, node in enumerate(input_nodes):
|
||||
node.location.x = -175
|
||||
node.location.y = i * -50
|
||||
group_input_node.location.x = -350
|
||||
|
||||
# Connect outputs to store named attribute nodes to replace modifier attribute outputs.
|
||||
store_nodes = []
|
||||
first_geometry_output = None
|
||||
for output_socket in old_group.outputs:
|
||||
identifier = output_socket.identifier
|
||||
group_node_output = get_socket_with_identifier(group_node.outputs, identifier)
|
||||
attribute_name = modifier_attribute_name_get(modifier, identifier)
|
||||
if attribute_name:
|
||||
store_node = group.nodes.new("GeometryNodeStoreNamedAttribute")
|
||||
store_nodes.append(store_node)
|
||||
store_node.data_type = socket_idname_to_attribute_type(output_socket.bl_socket_idname)
|
||||
store_node.domain = output_socket.attribute_domain
|
||||
store_node.inputs["Name"].default_value = attribute_name
|
||||
input_socket = get_enabled_socket_with_name(store_node.inputs, "Value")
|
||||
group.links.new(group_node_output, input_socket)
|
||||
elif output_socket.bl_socket_idname == 'NodeSocketGeometry':
|
||||
if not first_geometry_output:
|
||||
first_geometry_output = group_node_output
|
||||
|
||||
# Adjust locations of store named attribute nodes and move group output.
|
||||
if store_nodes:
|
||||
for i, node in enumerate(store_nodes):
|
||||
node.location.x = (i + 1) * 175
|
||||
node.location.y = 0
|
||||
group_output_node.location.x = (len(store_nodes) + 1) * 175
|
||||
|
||||
group.links.new(first_geometry_output, store_nodes[0].inputs["Geometry"])
|
||||
for i in range(len(store_nodes) - 1):
|
||||
group.links.new(store_nodes[i].outputs["Geometry"], store_nodes[i + 1].inputs["Geometry"])
|
||||
group.links.new(store_nodes[-1].outputs["Geometry"], group_output_node.inputs["Geometry"])
|
||||
else:
|
||||
group.links.new(first_geometry_output, group_output_node.inputs["Geometry"])
|
||||
|
||||
modifier.node_group = group
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class NewGeometryNodesModifier(Operator):
|
||||
"""Create a new modifier with a new geometry node group"""
|
||||
|
||||
|
@ -48,7 +204,6 @@ class NewGeometryNodesModifier(Operator):
|
|||
|
||||
def execute(self, context):
|
||||
modifier = context.object.modifiers.new(data_("GeometryNodes"), "NODES")
|
||||
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
@ -70,11 +225,7 @@ class NewGeometryNodeTreeAssign(Operator):
|
|||
return geometry_modifier_poll(context)
|
||||
|
||||
def execute(self, context):
|
||||
if context.area.type == 'PROPERTIES':
|
||||
modifier = context.modifier
|
||||
else:
|
||||
modifier = context.object.modifiers.active
|
||||
|
||||
modifier = get_context_modifier(context)
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
@ -87,4 +238,5 @@ class NewGeometryNodeTreeAssign(Operator):
|
|||
classes = (
|
||||
NewGeometryNodesModifier,
|
||||
NewGeometryNodeTreeAssign,
|
||||
MoveModifierToNodes,
|
||||
)
|
||||
|
|
|
@ -36,67 +36,136 @@ class ObjectModeOperator:
|
|||
|
||||
|
||||
class QuickFur(ObjectModeOperator, Operator):
|
||||
"""Add fur setup to the selected objects"""
|
||||
"""Add a fur setup to the selected objects"""
|
||||
bl_idname = "object.quick_fur"
|
||||
bl_label = "Quick Fur"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
density: EnumProperty(
|
||||
name="Fur Density",
|
||||
name="Density",
|
||||
items=(
|
||||
('LIGHT', "Light", ""),
|
||||
('LOW', "Low", ""),
|
||||
('MEDIUM', "Medium", ""),
|
||||
('HEAVY', "Heavy", ""),
|
||||
('HIGH', "High", ""),
|
||||
),
|
||||
default='MEDIUM',
|
||||
)
|
||||
view_percentage: IntProperty(
|
||||
name="View %",
|
||||
min=1, max=100,
|
||||
soft_min=1, soft_max=100,
|
||||
default=10,
|
||||
)
|
||||
length: FloatProperty(
|
||||
name="Length",
|
||||
min=0.001, max=100,
|
||||
soft_min=0.01, soft_max=10,
|
||||
default=0.1,
|
||||
subtype='DISTANCE'
|
||||
)
|
||||
radius: FloatProperty(
|
||||
name="Hair Radius",
|
||||
min=0.0, max=10,
|
||||
soft_min=0.0001, soft_max=0.1,
|
||||
default=0.001,
|
||||
subtype='DISTANCE'
|
||||
)
|
||||
view_percentage: FloatProperty(
|
||||
name="View Percentage",
|
||||
min=0.0, max=1.0,
|
||||
default=1.0,
|
||||
subtype='FACTOR'
|
||||
)
|
||||
apply_hair_guides: BoolProperty(
|
||||
name="Apply Hair Guides",
|
||||
default=True,
|
||||
)
|
||||
use_noise: BoolProperty(
|
||||
name="Noise",
|
||||
default=True,
|
||||
)
|
||||
use_frizz: BoolProperty(
|
||||
name="Frizz",
|
||||
default=True,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
fake_context = context.copy()
|
||||
mesh_objects = [obj for obj in context.selected_objects
|
||||
if obj.type == 'MESH']
|
||||
|
||||
import os
|
||||
mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH']
|
||||
if not mesh_objects:
|
||||
self.report({'ERROR'}, "Select at least one mesh object")
|
||||
return {'CANCELLED'}
|
||||
|
||||
mat = bpy.data.materials.new("Fur Material")
|
||||
if self.density == 'LOW':
|
||||
count = 1000
|
||||
elif self.density == 'MEDIUM':
|
||||
count = 10000
|
||||
elif self.density == 'HIGH':
|
||||
count = 100000
|
||||
|
||||
for obj in mesh_objects:
|
||||
fake_context["object"] = obj
|
||||
bpy.ops.object.particle_system_add(fake_context)
|
||||
node_groups_to_append = {"Generate Hair Curves", "Set Hair Curve Profile", "Interpolate Hair Curves"}
|
||||
if self.use_noise:
|
||||
node_groups_to_append.add("Hair Curves Noise")
|
||||
if self.use_frizz:
|
||||
node_groups_to_append.add("Frizz Hair Curves")
|
||||
assets_directory = os.path.join(bpy.utils.system_resource('DATAFILES'),
|
||||
"assets",
|
||||
"geometry_nodes",
|
||||
"procedural_hair_node_assets.blend",
|
||||
"NodeTree")
|
||||
for name in node_groups_to_append:
|
||||
bpy.ops.wm.append(directory=assets_directory,
|
||||
filename=name,
|
||||
use_recursive=True,
|
||||
clear_asset_data=True,
|
||||
do_reuse_local_id=True)
|
||||
generate_group = bpy.data.node_groups["Generate Hair Curves"]
|
||||
interpolate_group = bpy.data.node_groups["Interpolate Hair Curves"]
|
||||
radius_group = bpy.data.node_groups["Set Hair Curve Profile"]
|
||||
noise_group = bpy.data.node_groups["Hair Curves Noise"] if self.use_noise else None
|
||||
frizz_group = bpy.data.node_groups["Frizz Hair Curves"] if self.use_frizz else None
|
||||
|
||||
psys = obj.particle_systems[-1]
|
||||
psys.settings.type = 'HAIR'
|
||||
material = bpy.data.materials.new("Fur Material")
|
||||
|
||||
if self.density == 'LIGHT':
|
||||
psys.settings.count = 100
|
||||
elif self.density == 'MEDIUM':
|
||||
psys.settings.count = 1000
|
||||
elif self.density == 'HEAVY':
|
||||
psys.settings.count = 10000
|
||||
for mesh_object in mesh_objects:
|
||||
mesh = mesh_object.data
|
||||
with context.temp_override(active_object=mesh_object):
|
||||
bpy.ops.object.curves_empty_hair_add()
|
||||
curves_object = context.active_object
|
||||
curves = curves_object.data
|
||||
curves.materials.append(material)
|
||||
|
||||
psys.settings.child_nbr = self.view_percentage
|
||||
psys.settings.hair_length = self.length
|
||||
psys.settings.use_strand_primitive = True
|
||||
psys.settings.use_hair_bspline = True
|
||||
psys.settings.child_type = 'INTERPOLATED'
|
||||
psys.settings.tip_radius = 0.25
|
||||
area = 0.0
|
||||
for poly in mesh.polygons:
|
||||
area += poly.area
|
||||
density = count / area
|
||||
|
||||
obj.data.materials.append(mat)
|
||||
psys.settings.material = len(obj.data.materials)
|
||||
generate_modifier = curves_object.modifiers.new(name="Generate", type='NODES')
|
||||
generate_modifier.node_group = generate_group
|
||||
generate_modifier["Input_2"] = mesh_object
|
||||
generate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
|
||||
generate_modifier["Input_20"] = self.length
|
||||
generate_modifier["Input_22"] = material
|
||||
generate_modifier["Input_15"] = density * 0.01
|
||||
curves_object.modifiers.move(1, 0)
|
||||
|
||||
radius_modifier = curves_object.modifiers.new(name="Set Hair Curve Profile", type='NODES')
|
||||
radius_modifier.node_group = radius_group
|
||||
radius_modifier["Input_3"] = self.radius
|
||||
|
||||
interpolate_modifier = curves_object.modifiers.new(name="Interpolate Hair Curves", type='NODES')
|
||||
interpolate_modifier.node_group = interpolate_group
|
||||
interpolate_modifier["Input_2"] = mesh_object
|
||||
interpolate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
|
||||
interpolate_modifier["Input_15"] = density
|
||||
interpolate_modifier["Input_17"] = self.view_percentage
|
||||
interpolate_modifier["Input_24"] = True
|
||||
|
||||
if noise_group:
|
||||
noise_modifier = curves_object.modifiers.new(name="Hair Curves Noise", type='NODES')
|
||||
noise_modifier.node_group = noise_group
|
||||
|
||||
if frizz_group:
|
||||
frizz_modifier = curves_object.modifiers.new(name="Frizz Hair Curves", type='NODES')
|
||||
frizz_modifier.node_group = frizz_group
|
||||
|
||||
if self.apply_hair_guides:
|
||||
with context.temp_override(object=curves_object):
|
||||
bpy.ops.object.modifier_apply(modifier=generate_modifier.name)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
|
|
@ -1249,7 +1249,31 @@ class WM_OT_doc_view_manual(Operator):
|
|||
# XXX, for some reason all RNA ID's are stored lowercase
|
||||
# Adding case into all ID's isn't worth the hassle so force lowercase.
|
||||
rna_id = rna_id.lower()
|
||||
|
||||
# NOTE: `fnmatch` in Python is slow as it translate the string to a regular-expression
|
||||
# which needs to be compiled (as of Python 3.11), this is slow enough to cause a noticeable
|
||||
# delay when opening manual links (approaching half a second).
|
||||
#
|
||||
# Resolve by matching characters that have a special meaning to `fnmatch`.
|
||||
# The characters that can occur as the first special character are `*?[`.
|
||||
# If any of these are used we must let `fnmatch` run its own matching logic.
|
||||
# However, in most cases a literal prefix is used making it considerably faster
|
||||
# to do a simple `startswith` check before performing a full match.
|
||||
# An alternative solution could be to use `fnmatch` from C which is significantly
|
||||
# faster than Python's, see !104581 for details.
|
||||
import re
|
||||
re_match_non_special = re.compile(r"^[^?\*\[]+").match
|
||||
|
||||
for pattern, url_suffix in url_mapping:
|
||||
|
||||
# Simple optimization, makes a big difference (over 50x speedup).
|
||||
# Even when `non_special.end()` is zero (resulting in an empty-string),
|
||||
# the `startswith` check succeeds so there is no need to check for an empty match.
|
||||
non_special = re_match_non_special(pattern)
|
||||
if non_special is None or not rna_id.startswith(pattern[:non_special.end()]):
|
||||
continue
|
||||
# End simple optimization.
|
||||
|
||||
if fnmatchcase(rna_id, pattern):
|
||||
if verbose:
|
||||
print(" match found: '%s' --> '%s'" % (pattern, url_suffix))
|
||||
|
|
|
@ -604,7 +604,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
|
|||
colliding_names = []
|
||||
for collection in (
|
||||
# Built-in names.
|
||||
{"shade_smooth": None, "normal": None, "crease": None},
|
||||
{"shade_smooth": None, "crease": None},
|
||||
mesh.attributes,
|
||||
None if ob is None else ob.vertex_groups,
|
||||
):
|
||||
|
|
|
@ -1141,6 +1141,11 @@ def brush_texture_settings(layout, brush, sculpt):
|
|||
# texture_sample_bias
|
||||
layout.prop(brush, "texture_sample_bias", slider=True, text="Sample Bias")
|
||||
|
||||
if brush.sculpt_tool == 'DRAW':
|
||||
col = layout.column()
|
||||
col.active = tex_slot.map_mode == 'AREA_PLANE'
|
||||
col.prop(brush, "use_color_as_displacement", text="Vector Displacement")
|
||||
|
||||
|
||||
def brush_mask_texture_settings(layout, brush):
|
||||
mask_tex_slot = brush.mask_texture_slot
|
||||
|
|
|
@ -22,7 +22,7 @@ class FILEBROWSER_HT_header(Header):
|
|||
|
||||
layout.separator_spacer()
|
||||
|
||||
if params.asset_library_ref != 'LOCAL':
|
||||
if params.asset_library_ref not in {'LOCAL', 'ESSENTIALS'}:
|
||||
layout.prop(params, "import_type", text="")
|
||||
|
||||
layout.separator_spacer()
|
||||
|
|
|
@ -931,8 +931,14 @@ class SEQUENCER_MT_strip(Menu):
|
|||
|
||||
if has_sequencer:
|
||||
|
||||
layout.operator("sequencer.split", text="Split").type = 'SOFT'
|
||||
layout.operator("sequencer.split", text="Hold Split").type = 'HARD'
|
||||
props = layout.operator("sequencer.split", text="Split")
|
||||
props.type = 'SOFT'
|
||||
props.side = 'RIGHT'
|
||||
|
||||
props = layout.operator("sequencer.split", text="Hold Split")
|
||||
props.type = 'HARD'
|
||||
props.side = 'RIGHT'
|
||||
|
||||
layout.separator()
|
||||
|
||||
if has_sequencer:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1424,34 +1424,40 @@ class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel):
|
|||
layout.use_property_decorate = False
|
||||
|
||||
paths = context.preferences.filepaths
|
||||
active_library_index = paths.active_asset_library
|
||||
|
||||
box = layout.box()
|
||||
split = box.split(factor=0.35)
|
||||
name_col = split.column()
|
||||
path_col = split.column()
|
||||
row = layout.row()
|
||||
|
||||
row = name_col.row(align=True) # Padding
|
||||
row.separator()
|
||||
row.label(text="Name")
|
||||
row.template_list(
|
||||
"USERPREF_UL_asset_libraries", "user_asset_libraries",
|
||||
paths, "asset_libraries",
|
||||
paths, "active_asset_library"
|
||||
)
|
||||
|
||||
row = path_col.row(align=True) # Padding
|
||||
row.separator()
|
||||
row.label(text="Path")
|
||||
col = row.column(align=True)
|
||||
col.operator("preferences.asset_library_add", text="", icon='ADD')
|
||||
props = col.operator("preferences.asset_library_remove", text="", icon='REMOVE')
|
||||
props.index = active_library_index
|
||||
|
||||
for i, library in enumerate(paths.asset_libraries):
|
||||
row = name_col.row()
|
||||
row.alert = not library.name
|
||||
row.prop(library, "name", text="")
|
||||
if active_library_index < 0:
|
||||
return
|
||||
|
||||
row = path_col.row()
|
||||
subrow = row.row()
|
||||
subrow.alert = not library.path
|
||||
subrow.prop(library, "path", text="")
|
||||
row.operator("preferences.asset_library_remove", text="", icon='X', emboss=False).index = i
|
||||
layout.separator()
|
||||
|
||||
row = box.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False)
|
||||
active_library = paths.asset_libraries[active_library_index]
|
||||
layout.prop(active_library, "path")
|
||||
layout.prop(active_library, "import_method", text="Import Method")
|
||||
|
||||
|
||||
class USERPREF_UL_asset_libraries(bpy.types.UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
asset_library = item
|
||||
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
layout.prop(asset_library, "name", text="", emboss=False)
|
||||
elif self.layout_type == 'GRID':
|
||||
layout.alignment = 'CENTER'
|
||||
layout.prop(asset_library, "name", text="", emboss=False)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
@ -2319,21 +2325,15 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
|
|||
bl_label = "New Features"
|
||||
|
||||
def draw(self, context):
|
||||
self._draw_items(context,
|
||||
(({"property": "use_sculpt_tools_tilt"},
|
||||
("blender/blender/issues/82877",
|
||||
"#82877")),
|
||||
({"property": "use_extended_asset_browser"},
|
||||
("blender/blender/projects/10",
|
||||
"Pipeline, Assets & IO Project Page")),
|
||||
({"property": "use_override_templates"},
|
||||
("blender/blender/issues/73318",
|
||||
"Milestone 4")),
|
||||
({"property": "use_new_volume_nodes"},
|
||||
("blender/blender/issues/103248",
|
||||
"#103248")),
|
||||
),
|
||||
)
|
||||
self._draw_items(
|
||||
context, (
|
||||
({"property": "use_sculpt_tools_tilt"}, ("blender/blender/issues/82877", "#82877")),
|
||||
({"property": "use_extended_asset_browser"},
|
||||
("blender/blender/projects/10", "Pipeline, Assets & IO Project Page")),
|
||||
({"property": "use_override_templates"}, ("blender/blender/issues/73318", "Milestone 4")),
|
||||
({"property": "use_new_volume_nodes"}, ("blender/blender/issues/103248", "#103248")),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
|
||||
|
@ -2493,6 +2493,9 @@ classes = (
|
|||
# USERPREF_PT_experimental_tweaks,
|
||||
USERPREF_PT_experimental_debugging,
|
||||
|
||||
# UI lists
|
||||
USERPREF_UL_asset_libraries,
|
||||
|
||||
# Add dynamically generated editor theme panels last,
|
||||
# so they show up last in the theme section.
|
||||
*ThemeGenericClassGenerator.generate_panel_classes_from_theme_areas(),
|
||||
|
|
|
@ -522,7 +522,8 @@ class _draw_tool_settings_context_mode:
|
|||
|
||||
if curves_tool == 'COMB':
|
||||
layout.prop(brush, "falloff_shape", expand=True)
|
||||
layout.popover("VIEW3D_PT_tools_brush_falloff")
|
||||
layout.popover("VIEW3D_PT_tools_brush_falloff", text="Brush Falloff")
|
||||
layout.popover("VIEW3D_PT_curves_sculpt_parameter_falloff", text="Curve Falloff")
|
||||
elif curves_tool == 'ADD':
|
||||
layout.prop(brush, "falloff_shape", expand=True)
|
||||
layout.prop(brush.curves_sculpt_settings, "add_amount")
|
||||
|
@ -2043,6 +2044,16 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
|
|||
layout.operator("paint.vert_select_linked", text="Select Linked")
|
||||
|
||||
|
||||
class VIEW3D_MT_edit_curves_select_more_less(Menu):
|
||||
bl_label = "Select More/Less"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("curves.select_more", text="More")
|
||||
layout.operator("curves.select_less", text="Less")
|
||||
|
||||
|
||||
class VIEW3D_MT_select_edit_curves(Menu):
|
||||
bl_label = "Select"
|
||||
|
||||
|
@ -2052,10 +2063,17 @@ class VIEW3D_MT_select_edit_curves(Menu):
|
|||
layout.operator("curves.select_all", text="All").action = 'SELECT'
|
||||
layout.operator("curves.select_all", text="None").action = 'DESELECT'
|
||||
layout.operator("curves.select_all", text="Invert").action = 'INVERT'
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("curves.select_random", text="Random")
|
||||
layout.operator("curves.select_end", text="Endpoints")
|
||||
layout.operator("curves.select_linked", text="Linked")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.menu("VIEW3D_MT_edit_curves_select_more_less")
|
||||
|
||||
|
||||
class VIEW3D_MT_select_sculpt_curves(Menu):
|
||||
bl_label = "Select"
|
||||
|
@ -2116,6 +2134,7 @@ class VIEW3D_MT_curve_add(Menu):
|
|||
layout.separator()
|
||||
|
||||
layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA')
|
||||
layout.operator("object.quick_fur", text="Fur", icon='CURVES_DATA')
|
||||
|
||||
experimental = context.preferences.experimental
|
||||
if experimental.use_new_curves_tools:
|
||||
|
@ -3929,6 +3948,7 @@ class VIEW3D_MT_edit_mesh(Menu):
|
|||
layout.menu("VIEW3D_MT_edit_mesh_normals")
|
||||
layout.menu("VIEW3D_MT_edit_mesh_shading")
|
||||
layout.menu("VIEW3D_MT_edit_mesh_weights")
|
||||
layout.operator("mesh.attribute_set")
|
||||
layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
|
||||
|
||||
layout.separator()
|
||||
|
@ -5370,6 +5390,7 @@ class VIEW3D_MT_edit_curves(Menu):
|
|||
|
||||
layout.menu("VIEW3D_MT_transform")
|
||||
layout.separator()
|
||||
layout.operator("curves.delete")
|
||||
|
||||
|
||||
class VIEW3D_MT_object_mode_pie(Menu):
|
||||
|
@ -6780,15 +6801,15 @@ class VIEW3D_PT_overlay_sculpt(Panel):
|
|||
overlay = view.overlay
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(overlay, "sculpt_show_mask", text="")
|
||||
row.prop(overlay, "show_sculpt_mask", text="")
|
||||
sub = row.row()
|
||||
sub.active = overlay.sculpt_show_mask
|
||||
sub.active = overlay.show_sculpt_mask
|
||||
sub.prop(overlay, "sculpt_mode_mask_opacity", text="Mask")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(overlay, "sculpt_show_face_sets", text="")
|
||||
row.prop(overlay, "show_sculpt_face_sets", text="")
|
||||
sub = row.row()
|
||||
sub.active = overlay.sculpt_show_face_sets
|
||||
sub.active = overlay.show_sculpt_face_sets
|
||||
row.prop(overlay, "sculpt_mode_face_sets_opacity", text="Face Sets")
|
||||
|
||||
|
||||
|
@ -6815,6 +6836,13 @@ class VIEW3D_PT_overlay_sculpt_curves(Panel):
|
|||
row.active = overlay.show_overlays
|
||||
row.prop(overlay, "sculpt_mode_mask_opacity", text="Selection Opacity")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.active = overlay.show_overlays
|
||||
row.prop(overlay, "show_sculpt_curves_cage", text="")
|
||||
subrow = row.row(align=True)
|
||||
subrow.active = overlay.show_sculpt_curves_cage
|
||||
subrow.prop(overlay, "sculpt_curves_cage_opacity", text="Cage Opacity")
|
||||
|
||||
|
||||
class VIEW3D_PT_overlay_bones(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
|
@ -7996,6 +8024,28 @@ class VIEW3D_PT_curves_sculpt_add_shape(Panel):
|
|||
col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points")
|
||||
|
||||
|
||||
class VIEW3D_PT_curves_sculpt_parameter_falloff(Panel):
|
||||
# Only for popover, these are dummy values.
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_label = "Curves Sculpt Parameter Falloff"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
settings = UnifiedPaintPanel.paint_settings(context)
|
||||
brush = settings.brush
|
||||
|
||||
layout.template_curve_mapping(brush.curves_sculpt_settings, "curve_parameter_falloff")
|
||||
row = layout.row(align=True)
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.sculpt_curves_falloff_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
|
||||
|
||||
class VIEW3D_PT_curves_sculpt_grow_shrink_scaling(Panel):
|
||||
# Only for popover, these are dummy values.
|
||||
bl_space_type = 'VIEW_3D'
|
||||
|
@ -8073,6 +8123,7 @@ classes = (
|
|||
VIEW3D_MT_select_gpencil,
|
||||
VIEW3D_MT_select_paint_mask,
|
||||
VIEW3D_MT_select_paint_mask_vertex,
|
||||
VIEW3D_MT_edit_curves_select_more_less,
|
||||
VIEW3D_MT_select_edit_curves,
|
||||
VIEW3D_MT_select_sculpt_curves,
|
||||
VIEW3D_MT_mesh_add,
|
||||
|
@ -8273,6 +8324,7 @@ classes = (
|
|||
TOPBAR_PT_gpencil_vertexcolor,
|
||||
TOPBAR_PT_annotation_layers,
|
||||
VIEW3D_PT_curves_sculpt_add_shape,
|
||||
VIEW3D_PT_curves_sculpt_parameter_falloff,
|
||||
VIEW3D_PT_curves_sculpt_grow_shrink_scaling,
|
||||
VIEW3D_PT_viewport_debug,
|
||||
)
|
||||
|
|
|
@ -58,6 +58,11 @@ class AssetLibrary {
|
|||
|
||||
std::function<void(AssetLibrary &self)> on_refresh_;
|
||||
|
||||
std::optional<eAssetImportMethod> import_method_;
|
||||
/** Assets owned by this library may be imported with a different method than set in
|
||||
* #import_method_ above, it's just a default. */
|
||||
bool may_override_import_method_ = false;
|
||||
|
||||
bCallbackFuncStore on_save_callback_store_{};
|
||||
|
||||
public:
|
||||
|
@ -68,6 +73,7 @@ class AssetLibrary {
|
|||
std::unique_ptr<AssetCatalogService> catalog_service;
|
||||
|
||||
friend class AssetLibraryService;
|
||||
friend class AssetRepresentation;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -22,6 +22,8 @@ const char *AS_asset_representation_name_get(const AssetRepresentation *asset)
|
|||
AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT;
|
||||
bool AS_asset_representation_is_never_link(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -12,10 +12,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "DNA_asset_types.h"
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
|
||||
struct AssetMetaData;
|
||||
|
@ -70,6 +73,15 @@ class AssetRepresentation {
|
|||
|
||||
StringRefNull get_name() const;
|
||||
AssetMetaData &get_metadata() const;
|
||||
/** Get the import method to use for this asset. A different one may be used if
|
||||
* #may_override_import_method() returns true, otherwise, the returned value must be used. If
|
||||
* there is no import method predefined for this asset no value is returned.
|
||||
*/
|
||||
std::optional<eAssetImportMethod> get_import_method() const;
|
||||
/** Returns if this asset may be imported with an import method other than the one returned by
|
||||
* #get_import_method(). Also returns true if there is no predefined import method
|
||||
* (when #get_import_method() returns no value). */
|
||||
bool may_override_import_method() const;
|
||||
/** Returns if this asset is stored inside this current file, and as such fully editable. */
|
||||
bool is_local_id() const;
|
||||
const AssetLibrary &owner_asset_library() const;
|
||||
|
@ -81,3 +93,6 @@ class AssetRepresentation {
|
|||
struct AssetRepresentation;
|
||||
|
||||
const std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);
|
||||
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
|
||||
const ::AssetRepresentation *asset_handle);
|
||||
bool AS_asset_representation_may_override_import_method(const ::AssetRepresentation *asset_handle);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup asset_system
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
StringRefNull essentials_directory_path();
|
||||
|
||||
}
|
|
@ -17,6 +17,7 @@ set(SRC
|
|||
intern/asset_catalog.cc
|
||||
intern/asset_catalog_path.cc
|
||||
intern/asset_catalog_tree.cc
|
||||
intern/asset_essentials_library.cc
|
||||
intern/asset_identifier.cc
|
||||
intern/asset_library.cc
|
||||
intern/asset_library_service.cc
|
||||
|
@ -30,6 +31,7 @@ set(SRC
|
|||
AS_asset_identifier.hh
|
||||
AS_asset_library.hh
|
||||
AS_asset_representation.hh
|
||||
AS_essentials_library.hh
|
||||
intern/asset_library_service.hh
|
||||
intern/asset_storage.hh
|
||||
intern/utils.hh
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup asset_system
|
||||
*/
|
||||
|
||||
#include "BLI_path_util.h"
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
|
||||
#include "AS_essentials_library.hh"
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
StringRefNull essentials_directory_path()
|
||||
{
|
||||
static std::string path = []() {
|
||||
const char *datafiles_path = BKE_appdir_folder_id(BLENDER_DATAFILES, "assets");
|
||||
return datafiles_path;
|
||||
}();
|
||||
return path;
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system
|
|
@ -260,6 +260,12 @@ StringRefNull AssetLibrary::root_path() const
|
|||
Vector<AssetLibraryReference> all_valid_asset_library_refs()
|
||||
{
|
||||
Vector<AssetLibraryReference> result;
|
||||
{
|
||||
AssetLibraryReference library_ref{};
|
||||
library_ref.custom_library_index = -1;
|
||||
library_ref.type = ASSET_LIBRARY_ESSENTIALS;
|
||||
result.append(library_ref);
|
||||
}
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (const bUserAssetLibrary *, asset_library, &U.asset_libraries, i) {
|
||||
if (!BLI_is_dir(asset_library->path)) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "AS_asset_catalog_tree.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
#include "AS_essentials_library.hh"
|
||||
#include "asset_library_service.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
|
@ -60,6 +61,14 @@ AssetLibrary *AssetLibraryService::get_asset_library(
|
|||
const eAssetLibraryType type = eAssetLibraryType(library_reference.type);
|
||||
|
||||
switch (type) {
|
||||
case ASSET_LIBRARY_ESSENTIALS: {
|
||||
const StringRefNull root_path = essentials_directory_path();
|
||||
|
||||
AssetLibrary *library = get_asset_library_on_disk(root_path);
|
||||
library->import_method_ = ASSET_IMPORT_APPEND_REUSE;
|
||||
|
||||
return library;
|
||||
}
|
||||
case ASSET_LIBRARY_LOCAL: {
|
||||
/* For the "Current File" library we get the asset library root path based on main. */
|
||||
std::string root_path = bmain ? AS_asset_library_find_suitable_root_path_from_main(bmain) :
|
||||
|
@ -74,12 +83,22 @@ AssetLibrary *AssetLibraryService::get_asset_library(
|
|||
case ASSET_LIBRARY_ALL:
|
||||
return get_asset_library_all(bmain);
|
||||
case ASSET_LIBRARY_CUSTOM: {
|
||||
std::string root_path = root_path_from_library_ref(library_reference);
|
||||
|
||||
if (!root_path.empty()) {
|
||||
return get_asset_library_on_disk(root_path);
|
||||
bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
|
||||
library_reference);
|
||||
if (!custom_library) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
std::string root_path = custom_library->path;
|
||||
if (root_path.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AssetLibrary *library = get_asset_library_on_disk(root_path);
|
||||
library->import_method_ = eAssetImportMethod(custom_library->import_method);
|
||||
library->may_override_import_method_ = true;
|
||||
|
||||
return library;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +199,15 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
|
|||
return all_library_.get();
|
||||
}
|
||||
|
||||
bUserAssetLibrary *AssetLibraryService::find_custom_asset_library_from_library_ref(
|
||||
const AssetLibraryReference &library_reference)
|
||||
{
|
||||
BLI_assert(library_reference.type == ASSET_LIBRARY_CUSTOM);
|
||||
BLI_assert(library_reference.custom_library_index >= 0);
|
||||
|
||||
return BKE_preferences_asset_library_find_from_index(&U, library_reference.custom_library_index);
|
||||
}
|
||||
|
||||
std::string AssetLibraryService::root_path_from_library_ref(
|
||||
const AssetLibraryReference &library_reference)
|
||||
{
|
||||
|
@ -187,16 +215,13 @@ std::string AssetLibraryService::root_path_from_library_ref(
|
|||
return "";
|
||||
}
|
||||
|
||||
BLI_assert(library_reference.type == ASSET_LIBRARY_CUSTOM);
|
||||
BLI_assert(library_reference.custom_library_index >= 0);
|
||||
|
||||
bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
|
||||
&U, library_reference.custom_library_index);
|
||||
if (!user_library || !user_library->path[0]) {
|
||||
bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
|
||||
library_reference);
|
||||
if (!custom_library || !custom_library->path[0]) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return user_library->path;
|
||||
return custom_library->path;
|
||||
}
|
||||
|
||||
void AssetLibraryService::allocate_service_instance()
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <memory>
|
||||
|
||||
struct AssetLibraryReference;
|
||||
struct bUserAssetLibrary;
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
|
@ -58,6 +59,8 @@ class AssetLibraryService {
|
|||
static void destroy();
|
||||
|
||||
static std::string root_path_from_library_ref(const AssetLibraryReference &library_reference);
|
||||
static bUserAssetLibrary *find_custom_asset_library_from_library_ref(
|
||||
const AssetLibraryReference &library_reference);
|
||||
|
||||
AssetLibrary *get_asset_library(const Main *bmain,
|
||||
const AssetLibraryReference &library_reference);
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_asset_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
#include "AS_asset_representation.h"
|
||||
#include "AS_asset_representation.hh"
|
||||
|
||||
|
@ -79,6 +81,22 @@ AssetMetaData &AssetRepresentation::get_metadata() const
|
|||
return is_local_id_ ? *local_asset_id_->asset_data : *external_asset_.metadata_;
|
||||
}
|
||||
|
||||
std::optional<eAssetImportMethod> AssetRepresentation::get_import_method() const
|
||||
{
|
||||
if (!owner_asset_library_) {
|
||||
return {};
|
||||
}
|
||||
return owner_asset_library_->import_method_;
|
||||
}
|
||||
|
||||
bool AssetRepresentation::may_override_import_method() const
|
||||
{
|
||||
if (!owner_asset_library_ || !owner_asset_library_->import_method_) {
|
||||
return true;
|
||||
}
|
||||
return owner_asset_library_->may_override_import_method_;
|
||||
}
|
||||
|
||||
bool AssetRepresentation::is_local_id() const
|
||||
{
|
||||
return is_local_id_;
|
||||
|
@ -101,6 +119,21 @@ const std::string AS_asset_representation_full_path_get(const AssetRepresentatio
|
|||
return identifier.full_path();
|
||||
}
|
||||
|
||||
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
|
||||
const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->get_import_method();
|
||||
}
|
||||
|
||||
bool AS_asset_representation_may_override_import_method(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->may_override_import_method();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name C-API
|
||||
* \{ */
|
||||
|
|
|
@ -41,6 +41,7 @@ typedef enum eAttrDomainMask {
|
|||
ATTR_DOMAIN_MASK_CURVE = (1 << 4),
|
||||
ATTR_DOMAIN_MASK_ALL = (1 << 5) - 1
|
||||
} eAttrDomainMask;
|
||||
ENUM_OPERATORS(eAttrDomainMask, ATTR_DOMAIN_MASK_ALL);
|
||||
|
||||
#define ATTR_DOMAIN_AS_MASK(domain) ((eAttrDomainMask)((1 << (int)(domain))))
|
||||
|
||||
|
|
|
@ -17,15 +17,17 @@ extern "C" {
|
|||
*/
|
||||
|
||||
/* Blender major and minor version. */
|
||||
#define BLENDER_VERSION 305
|
||||
#define BLENDER_VERSION 306
|
||||
/* Blender patch version for bugfix releases. */
|
||||
#define BLENDER_VERSION_PATCH 0
|
||||
/** Blender release cycle stage: alpha/beta/rc/release. */
|
||||
#define BLENDER_VERSION_CYCLE alpha
|
||||
|
||||
/* TODO proper version bump. */
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 9
|
||||
#define BLENDER_FILE_SUBVERSION 0
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
|
|
@ -108,7 +108,7 @@ BVHTree *bvhtree_from_editmesh_verts(
|
|||
*/
|
||||
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
|
||||
struct BMEditMesh *em,
|
||||
const blender::BitVector<> &mask,
|
||||
blender::BitSpan mask,
|
||||
int verts_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -124,7 +124,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
|
|||
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
|
||||
const float (*vert_positions)[3],
|
||||
int verts_num,
|
||||
const blender::BitVector<> &verts_mask,
|
||||
blender::BitSpan verts_mask,
|
||||
int verts_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -138,7 +138,7 @@ BVHTree *bvhtree_from_editmesh_edges(
|
|||
*/
|
||||
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
|
||||
struct BMEditMesh *em,
|
||||
const blender::BitVector<> &edges_mask,
|
||||
blender::BitSpan edges_mask,
|
||||
int edges_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -156,7 +156,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
|
|||
const float (*vert_positions)[3],
|
||||
const struct MEdge *edge,
|
||||
int edges_num,
|
||||
const blender::BitVector<> &edges_mask,
|
||||
blender::BitSpan edges_mask,
|
||||
int edges_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -170,7 +170,7 @@ BVHTree *bvhtree_from_editmesh_looptri(
|
|||
*/
|
||||
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
|
||||
struct BMEditMesh *em,
|
||||
const blender::BitVector<> &mask,
|
||||
blender::BitSpan mask,
|
||||
int looptri_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -184,7 +184,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
|
|||
const struct MLoop *mloop,
|
||||
const struct MLoopTri *looptri,
|
||||
int looptri_num,
|
||||
const blender::BitVector<> &mask,
|
||||
blender::BitSpan mask,
|
||||
int looptri_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
|
|
@ -46,6 +46,7 @@ struct GeometryDeformation {
|
|||
* function either retrieves the deformation data from the evaluated object, or falls back to
|
||||
* returning the original data.
|
||||
*/
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig);
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
const Object &ob_orig);
|
||||
|
||||
|
|
|
@ -71,16 +71,11 @@ class CurvesGeometryRuntime {
|
|||
|
||||
mutable SharedCache<Vector<curves::nurbs::BasisCache>> nurbs_basis_cache;
|
||||
|
||||
/** Cache of evaluated positions. */
|
||||
struct EvaluatedPositions {
|
||||
Vector<float3> vector;
|
||||
/**
|
||||
* The evaluated positions result, using a separate span in case all curves are poly curves,
|
||||
* in which case a separate array of evaluated positions is unnecessary.
|
||||
*/
|
||||
Span<float3> span;
|
||||
};
|
||||
mutable SharedCache<EvaluatedPositions> evaluated_position_cache;
|
||||
/**
|
||||
* Cache of evaluated positions for all curves. The positions span will
|
||||
* be used directly rather than the cache when all curves are poly type.
|
||||
*/
|
||||
mutable SharedCache<Vector<float3>> evaluated_position_cache;
|
||||
|
||||
/**
|
||||
* A cache of bounds shared between data-blocks with unchanged positions and radii.
|
||||
|
|
|
@ -282,6 +282,7 @@ bool CustomData_has_layer(const struct CustomData *data, int type);
|
|||
* Returns the number of layers with this type.
|
||||
*/
|
||||
int CustomData_number_of_layers(const struct CustomData *data, int type);
|
||||
int CustomData_number_of_anonymous_layers(const struct CustomData *data, int type);
|
||||
int CustomData_number_of_layers_typemask(const struct CustomData *data, eCustomDataMask mask);
|
||||
|
||||
/**
|
||||
|
@ -305,8 +306,8 @@ void CustomData_copy_data(const struct CustomData *source,
|
|||
int source_index,
|
||||
int dest_index,
|
||||
int count);
|
||||
void CustomData_copy_data_layer(const CustomData *source,
|
||||
CustomData *dest,
|
||||
void CustomData_copy_data_layer(const struct CustomData *source,
|
||||
struct CustomData *dest,
|
||||
int src_layer_index,
|
||||
int dst_layer_index,
|
||||
int src_index,
|
||||
|
@ -445,7 +446,7 @@ void *CustomData_get_layer_named_for_write(CustomData *data,
|
|||
int totelem);
|
||||
|
||||
int CustomData_get_offset(const struct CustomData *data, int type);
|
||||
int CustomData_get_offset_named(const CustomData *data, int type, const char *name);
|
||||
int CustomData_get_offset_named(const struct CustomData *data, int type, const char *name);
|
||||
int CustomData_get_n_offset(const struct CustomData *data, int type, int n);
|
||||
|
||||
int CustomData_get_layer_index(const struct CustomData *data, int type);
|
||||
|
@ -520,7 +521,6 @@ void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
|
|||
void *block,
|
||||
eCustomDataMask mask_exclude);
|
||||
|
||||
|
||||
/**
|
||||
* Query info over types.
|
||||
*/
|
||||
|
@ -729,7 +729,7 @@ void CustomData_blend_write(BlendWriter *writer,
|
|||
|
||||
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
|
||||
|
||||
size_t CustomData_get_elem_size(struct CustomDataLayer *layer);
|
||||
size_t CustomData_get_elem_size(const struct CustomDataLayer *layer);
|
||||
|
||||
#ifndef NDEBUG
|
||||
struct DynStr;
|
||||
|
|
|
@ -41,10 +41,10 @@ struct PropertyRNA;
|
|||
*/
|
||||
void BKE_nlastrip_free(struct NlaStrip *strip, bool do_id_user);
|
||||
/**
|
||||
* Remove the given NLA track from the set of NLA tracks, free the track's data,
|
||||
* and the track itself.
|
||||
* Remove & Frees all NLA strips from the given NLA track,
|
||||
* then frees (doesn't remove) the track itself.
|
||||
*/
|
||||
void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user);
|
||||
void BKE_nlatrack_free(struct NlaTrack *nlt, bool do_id_user);
|
||||
/**
|
||||
* Free the elements of type NLA Tracks provided in the given list, but do not free
|
||||
* the list itself since that is not free-standing
|
||||
|
@ -95,6 +95,17 @@ struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt,
|
|||
struct NlaTrack *prev,
|
||||
bool is_liboverride);
|
||||
|
||||
/**
|
||||
* Removes the given NLA track from the list of tracks provided.
|
||||
*/
|
||||
void BKE_nlatrack_remove(ListBase *tracks, struct NlaTrack *nlt);
|
||||
|
||||
/**
|
||||
* Remove the given NLA track from the list of NLA tracks, free the track's data,
|
||||
* and the track itself.
|
||||
*/
|
||||
void BKE_nlatrack_remove_and_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user);
|
||||
|
||||
/**
|
||||
* Create a NLA Strip referencing the given Action.
|
||||
*/
|
||||
|
|
|
@ -249,8 +249,8 @@ set(SRC
|
|||
intern/particle_distribute.c
|
||||
intern/particle_system.c
|
||||
intern/pbvh.cc
|
||||
intern/pbvh_colors.cc
|
||||
intern/pbvh_bmesh.cc
|
||||
intern/pbvh_colors.cc
|
||||
intern/pbvh_pixels.cc
|
||||
intern/pbvh_uv_islands.cc
|
||||
intern/pointcache.c
|
||||
|
|
|
@ -316,9 +316,6 @@ GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const void *owner) cons
|
|||
|
||||
GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner) const
|
||||
{
|
||||
if (writable_ != Writable) {
|
||||
return {};
|
||||
}
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
||||
if (custom_data == nullptr) {
|
||||
return {};
|
||||
|
|
|
@ -37,10 +37,6 @@ class BuiltinAttributeProvider {
|
|||
Creatable,
|
||||
NonCreatable,
|
||||
};
|
||||
enum WritableEnum {
|
||||
Writable,
|
||||
Readonly,
|
||||
};
|
||||
enum DeletableEnum {
|
||||
Deletable,
|
||||
NonDeletable,
|
||||
|
@ -51,7 +47,6 @@ class BuiltinAttributeProvider {
|
|||
const eAttrDomain domain_;
|
||||
const eCustomDataType data_type_;
|
||||
const CreatableEnum createable_;
|
||||
const WritableEnum writable_;
|
||||
const DeletableEnum deletable_;
|
||||
const AttributeValidator validator_;
|
||||
|
||||
|
@ -60,14 +55,12 @@ class BuiltinAttributeProvider {
|
|||
const eAttrDomain domain,
|
||||
const eCustomDataType data_type,
|
||||
const CreatableEnum createable,
|
||||
const WritableEnum writable,
|
||||
const DeletableEnum deletable,
|
||||
AttributeValidator validator = {})
|
||||
: name_(std::move(name)),
|
||||
domain_(domain),
|
||||
data_type_(data_type),
|
||||
createable_(createable),
|
||||
writable_(writable),
|
||||
deletable_(deletable),
|
||||
validator_(validator)
|
||||
{
|
||||
|
@ -205,20 +198,14 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
|
|||
const eCustomDataType attribute_type,
|
||||
const eCustomDataType stored_type,
|
||||
const CreatableEnum creatable,
|
||||
const WritableEnum writable,
|
||||
const DeletableEnum deletable,
|
||||
const CustomDataAccessInfo custom_data_access,
|
||||
const AsReadAttribute as_read_attribute,
|
||||
const AsWriteAttribute as_write_attribute,
|
||||
const UpdateOnChange update_on_write,
|
||||
const AttributeValidator validator = {})
|
||||
: BuiltinAttributeProvider(std::move(attribute_name),
|
||||
domain,
|
||||
attribute_type,
|
||||
creatable,
|
||||
writable,
|
||||
deletable,
|
||||
validator),
|
||||
: BuiltinAttributeProvider(
|
||||
std::move(attribute_name), domain, attribute_type, creatable, deletable, validator),
|
||||
stored_type_(stored_type),
|
||||
custom_data_access_(custom_data_access),
|
||||
as_read_attribute_(as_read_attribute),
|
||||
|
|
|
@ -100,6 +100,8 @@ static void brush_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, cons
|
|||
if (brush_src->curves_sculpt_settings != nullptr) {
|
||||
brush_dst->curves_sculpt_settings = MEM_cnew<BrushCurvesSculptSettings>(
|
||||
__func__, *(brush_src->curves_sculpt_settings));
|
||||
brush_dst->curves_sculpt_settings->curve_parameter_falloff = BKE_curvemapping_copy(
|
||||
brush_src->curves_sculpt_settings->curve_parameter_falloff);
|
||||
}
|
||||
|
||||
/* enable fake user by default */
|
||||
|
@ -130,6 +132,7 @@ static void brush_free_data(ID *id)
|
|||
MEM_SAFE_FREE(brush->gpencil_settings);
|
||||
}
|
||||
if (brush->curves_sculpt_settings != nullptr) {
|
||||
BKE_curvemapping_free(brush->curves_sculpt_settings->curve_parameter_falloff);
|
||||
MEM_freeN(brush->curves_sculpt_settings);
|
||||
}
|
||||
|
||||
|
@ -255,6 +258,7 @@ static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_addres
|
|||
}
|
||||
if (brush->curves_sculpt_settings) {
|
||||
BLO_write_struct(writer, BrushCurvesSculptSettings, brush->curves_sculpt_settings);
|
||||
BKE_curvemapping_blend_write(writer, brush->curves_sculpt_settings->curve_parameter_falloff);
|
||||
}
|
||||
if (brush->gradient) {
|
||||
BLO_write_struct(writer, ColorBand, brush->gradient);
|
||||
|
@ -337,6 +341,12 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
}
|
||||
|
||||
BLO_read_data_address(reader, &brush->curves_sculpt_settings);
|
||||
if (brush->curves_sculpt_settings) {
|
||||
BLO_read_data_address(reader, &brush->curves_sculpt_settings->curve_parameter_falloff);
|
||||
if (brush->curves_sculpt_settings->curve_parameter_falloff) {
|
||||
BKE_curvemapping_blend_read(reader, brush->curves_sculpt_settings->curve_parameter_falloff);
|
||||
}
|
||||
}
|
||||
|
||||
brush->preview = nullptr;
|
||||
brush->icon_imbuf = nullptr;
|
||||
|
@ -1583,6 +1593,7 @@ void BKE_brush_init_curves_sculpt_settings(Brush *brush)
|
|||
settings->minimum_length = 0.01f;
|
||||
settings->curve_length = 0.3f;
|
||||
settings->density_add_attempts = 100;
|
||||
settings->curve_parameter_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using blender::BitSpan;
|
||||
using blender::BitVector;
|
||||
using blender::float3;
|
||||
using blender::IndexRange;
|
||||
|
@ -672,7 +673,7 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(float epsilon,
|
|||
int tree_type,
|
||||
int axis,
|
||||
BMEditMesh *em,
|
||||
const BitVector<> &verts_mask,
|
||||
const BitSpan verts_mask,
|
||||
int verts_num_active)
|
||||
{
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
|
@ -706,7 +707,7 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
|
|||
int axis,
|
||||
const float (*positions)[3],
|
||||
const int verts_num,
|
||||
const BitVector<> &verts_mask,
|
||||
const BitSpan verts_mask,
|
||||
int verts_num_active)
|
||||
{
|
||||
if (!verts_mask.is_empty()) {
|
||||
|
@ -737,7 +738,7 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
|
|||
|
||||
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
|
||||
BMEditMesh *em,
|
||||
const BitVector<> &verts_mask,
|
||||
const BitSpan verts_mask,
|
||||
int verts_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -764,7 +765,7 @@ BVHTree *bvhtree_from_editmesh_verts(
|
|||
BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
|
||||
const float (*vert_positions)[3],
|
||||
const int verts_num,
|
||||
const BitVector<> &verts_mask,
|
||||
const BitSpan verts_mask,
|
||||
int verts_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -794,7 +795,7 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
|
|||
int tree_type,
|
||||
int axis,
|
||||
BMEditMesh *em,
|
||||
const BitVector<> &edges_mask,
|
||||
const BitSpan edges_mask,
|
||||
int edges_num_active)
|
||||
{
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
|
||||
|
@ -833,7 +834,7 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
|
|||
static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
|
||||
const MEdge *edge,
|
||||
const int edge_num,
|
||||
const BitVector<> &edges_mask,
|
||||
const BitSpan edges_mask,
|
||||
int edges_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -871,7 +872,7 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
|
|||
|
||||
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
|
||||
BMEditMesh *em,
|
||||
const BitVector<> &edges_mask,
|
||||
const BitSpan edges_mask,
|
||||
int edges_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -899,7 +900,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
|
|||
const float (*vert_positions)[3],
|
||||
const MEdge *edge,
|
||||
const int edges_num,
|
||||
const BitVector<> &edges_mask,
|
||||
const BitSpan edges_mask,
|
||||
int edges_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -931,7 +932,7 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
|
|||
const float (*positions)[3],
|
||||
const MFace *face,
|
||||
const int faces_num,
|
||||
const BitVector<> &faces_mask,
|
||||
const BitSpan faces_mask,
|
||||
int faces_num_active)
|
||||
{
|
||||
if (faces_num == 0) {
|
||||
|
@ -984,7 +985,7 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
|
|||
int tree_type,
|
||||
int axis,
|
||||
BMEditMesh *em,
|
||||
const BitVector<> &looptri_mask,
|
||||
const BitSpan looptri_mask,
|
||||
int looptri_num_active)
|
||||
{
|
||||
const int looptri_num = em->tottri;
|
||||
|
@ -1038,7 +1039,7 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
|
|||
const MLoop *mloop,
|
||||
const MLoopTri *looptri,
|
||||
const int looptri_num,
|
||||
const BitVector<> &looptri_mask,
|
||||
const BitSpan looptri_mask,
|
||||
int looptri_num_active)
|
||||
{
|
||||
if (!looptri_mask.is_empty()) {
|
||||
|
@ -1079,7 +1080,7 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
|
|||
|
||||
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
|
||||
BMEditMesh *em,
|
||||
const BitVector<> &looptri_mask,
|
||||
const BitSpan looptri_mask,
|
||||
int looptri_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
@ -1109,7 +1110,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
|
|||
const struct MLoop *mloop,
|
||||
const struct MLoopTri *looptri,
|
||||
const int looptri_num,
|
||||
const BitVector<> &looptri_mask,
|
||||
const BitSpan looptri_mask,
|
||||
int looptri_num_active,
|
||||
float epsilon,
|
||||
int tree_type,
|
||||
|
|
|
@ -596,8 +596,7 @@ void BKE_crazyspace_api_eval_clear(Object *object)
|
|||
|
||||
namespace blender::bke::crazyspace {
|
||||
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
const Object &ob_orig)
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig)
|
||||
{
|
||||
BLI_assert(ob_orig.type == OB_CURVES);
|
||||
const Curves &curves_id_orig = *static_cast<const Curves *>(ob_orig.data);
|
||||
|
@ -608,7 +607,6 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
|||
/* Use the undeformed positions by default. */
|
||||
deformation.positions = curves_orig.positions();
|
||||
|
||||
const Object *ob_eval = DEG_get_evaluated_object(&depsgraph, const_cast<Object *>(&ob_orig));
|
||||
if (ob_eval == nullptr) {
|
||||
return deformation;
|
||||
}
|
||||
|
@ -653,4 +651,11 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
|||
return deformation;
|
||||
}
|
||||
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
const Object &ob_orig)
|
||||
{
|
||||
const Object *ob_eval = DEG_get_evaluated_object(&depsgraph, const_cast<Object *>(&ob_orig));
|
||||
return get_evaluated_curves_deformation(ob_eval, ob_orig);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::crazyspace
|
||||
|
|
|
@ -605,17 +605,15 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
|
|||
Span<float3> CurvesGeometry::evaluated_positions() const
|
||||
{
|
||||
const bke::CurvesGeometryRuntime &runtime = *this->runtime;
|
||||
if (this->is_single_type(CURVE_TYPE_POLY)) {
|
||||
runtime.evaluated_position_cache.ensure(
|
||||
[&](Vector<float3> &r_data) { r_data.clear_and_shrink(); });
|
||||
return this->positions();
|
||||
}
|
||||
this->ensure_nurbs_basis_cache();
|
||||
runtime.evaluated_position_cache.ensure([&](CurvesGeometryRuntime::EvaluatedPositions &r_data) {
|
||||
if (this->is_single_type(CURVE_TYPE_POLY)) {
|
||||
r_data.span = this->positions();
|
||||
r_data.vector.clear_and_shrink();
|
||||
return;
|
||||
}
|
||||
|
||||
r_data.vector.resize(this->evaluated_points_num());
|
||||
r_data.span = r_data.vector;
|
||||
MutableSpan<float3> evaluated_positions = r_data.vector;
|
||||
runtime.evaluated_position_cache.ensure([&](Vector<float3> &r_data) {
|
||||
r_data.resize(this->evaluated_points_num());
|
||||
MutableSpan<float3> evaluated_positions = r_data;
|
||||
|
||||
const OffsetIndices<int> points_by_curve = this->points_by_curve();
|
||||
const OffsetIndices<int> evaluated_points_by_curve = this->evaluated_points_by_curve();
|
||||
|
@ -672,7 +670,7 @@ Span<float3> CurvesGeometry::evaluated_positions() const
|
|||
}
|
||||
});
|
||||
});
|
||||
return runtime.evaluated_position_cache.data().span;
|
||||
return runtime.evaluated_position_cache.data();
|
||||
}
|
||||
|
||||
Span<float3> CurvesGeometry::evaluated_tangents() const
|
||||
|
@ -781,6 +779,7 @@ static void evaluate_generic_data_for_curve(
|
|||
Span<float3> CurvesGeometry::evaluated_normals() const
|
||||
{
|
||||
const bke::CurvesGeometryRuntime &runtime = *this->runtime;
|
||||
this->ensure_nurbs_basis_cache();
|
||||
runtime.evaluated_normal_cache.ensure([&](Vector<float3> &r_data) {
|
||||
const OffsetIndices<int> points_by_curve = this->points_by_curve();
|
||||
const OffsetIndices<int> evaluated_points_by_curve = this->evaluated_points_by_curve();
|
||||
|
|
|
@ -2991,6 +2991,19 @@ int CustomData_number_of_layers(const CustomData *data, const int type)
|
|||
return number;
|
||||
}
|
||||
|
||||
int CustomData_number_of_anonymous_layers(const CustomData *data, const int type)
|
||||
{
|
||||
int number = 0;
|
||||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
if (data->layers[i].type == type && data->layers[i].anonymous_id != nullptr) {
|
||||
number++;
|
||||
}
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
int CustomData_number_of_layers_typemask(const CustomData *data, const eCustomDataMask mask)
|
||||
{
|
||||
int number = 0;
|
||||
|
@ -5203,7 +5216,7 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
|
|||
|
||||
} // namespace blender::bke
|
||||
|
||||
size_t CustomData_get_elem_size(CustomDataLayer *layer)
|
||||
size_t CustomData_get_elem_size(const CustomDataLayer *layer)
|
||||
{
|
||||
return LAYERTYPEINFO[layer->type].size;
|
||||
}
|
||||
|
|
|
@ -375,7 +375,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_FLOAT3,
|
||||
CD_PROP_FLOAT3,
|
||||
BuiltinAttributeProvider::NonCreatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float3>,
|
||||
|
@ -387,7 +386,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_FLOAT,
|
||||
CD_PROP_FLOAT,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float>,
|
||||
|
@ -399,7 +397,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_INT32,
|
||||
CD_PROP_INT32,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<int>,
|
||||
|
@ -411,7 +408,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_FLOAT,
|
||||
CD_PROP_FLOAT,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float>,
|
||||
|
@ -423,7 +419,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_FLOAT3,
|
||||
CD_PROP_FLOAT3,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float3>,
|
||||
|
@ -435,7 +430,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_FLOAT3,
|
||||
CD_PROP_FLOAT3,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float3>,
|
||||
|
@ -453,7 +447,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_INT8,
|
||||
CD_PROP_INT8,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<int8_t>,
|
||||
|
@ -466,7 +459,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_INT8,
|
||||
CD_PROP_INT8,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<int8_t>,
|
||||
|
@ -479,7 +471,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_FLOAT,
|
||||
CD_PROP_FLOAT,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float>,
|
||||
|
@ -495,7 +486,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_INT8,
|
||||
CD_PROP_INT8,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
curve_access,
|
||||
make_array_read_attribute<int8_t>,
|
||||
|
@ -514,7 +504,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_INT8,
|
||||
CD_PROP_INT8,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
curve_access,
|
||||
make_array_read_attribute<int8_t>,
|
||||
|
@ -533,7 +522,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_INT8,
|
||||
CD_PROP_INT8,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
curve_access,
|
||||
make_array_read_attribute<int8_t>,
|
||||
|
@ -552,7 +540,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_INT8,
|
||||
CD_PROP_INT8,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
curve_access,
|
||||
make_array_read_attribute<int8_t>,
|
||||
|
@ -569,7 +556,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_INT32,
|
||||
CD_PROP_INT32,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
curve_access,
|
||||
make_array_read_attribute<int>,
|
||||
|
@ -582,7 +568,6 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
|||
CD_PROP_BOOL,
|
||||
CD_PROP_BOOL,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
curve_access,
|
||||
make_array_read_attribute<bool>,
|
||||
|
|
|
@ -129,7 +129,7 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
|
|||
public:
|
||||
InstancePositionAttributeProvider()
|
||||
: BuiltinAttributeProvider(
|
||||
"position", ATTR_DOMAIN_INSTANCE, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable)
|
||||
"position", ATTR_DOMAIN_INSTANCE, CD_PROP_FLOAT3, NonCreatable, NonDeletable)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,6 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
|
|||
CD_PROP_INT32,
|
||||
CD_PROP_INT32,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
instance_custom_data_access,
|
||||
make_array_read_attribute<int>,
|
||||
|
|
|
@ -1137,48 +1137,6 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This provider makes face normals available as a read-only float3 attribute.
|
||||
*/
|
||||
class NormalAttributeProvider final : public BuiltinAttributeProvider {
|
||||
public:
|
||||
NormalAttributeProvider()
|
||||
: BuiltinAttributeProvider(
|
||||
"normal", ATTR_DOMAIN_FACE, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable)
|
||||
{
|
||||
}
|
||||
|
||||
GVArray try_get_for_read(const void *owner) const final
|
||||
{
|
||||
const Mesh *mesh = static_cast<const Mesh *>(owner);
|
||||
if (mesh == nullptr || mesh->totpoly == 0) {
|
||||
return {};
|
||||
}
|
||||
return VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly});
|
||||
}
|
||||
|
||||
GAttributeWriter try_get_for_write(void * /*owner*/) const final
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool try_delete(void * /*owner*/) const final
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_create(void * /*owner*/, const AttributeInit & /*initializer*/) const final
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool exists(const void *owner) const final
|
||||
{
|
||||
const Mesh *mesh = static_cast<const Mesh *>(owner);
|
||||
return mesh->totpoly != 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* In this function all the attribute providers for a mesh component are created. Most data in this
|
||||
* function is statically allocated, because it does not change over time.
|
||||
|
@ -1222,21 +1180,17 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
|||
CD_PROP_FLOAT3,
|
||||
CD_PROP_FLOAT3,
|
||||
BuiltinAttributeProvider::NonCreatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float3>,
|
||||
make_array_write_attribute<float3>,
|
||||
tag_component_positions_changed);
|
||||
|
||||
static NormalAttributeProvider normal;
|
||||
|
||||
static BuiltinCustomDataLayerProvider id("id",
|
||||
ATTR_DOMAIN_POINT,
|
||||
CD_PROP_INT32,
|
||||
CD_PROP_INT32,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<int>,
|
||||
|
@ -1255,7 +1209,6 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
|||
CD_PROP_INT32,
|
||||
CD_PROP_INT32,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
face_access,
|
||||
make_array_read_attribute<int>,
|
||||
|
@ -1269,7 +1222,6 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
|||
CD_PROP_BOOL,
|
||||
CD_MPOLY,
|
||||
BuiltinAttributeProvider::NonCreatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
face_access,
|
||||
make_derived_read_attribute<MPoly, bool, get_shade_smooth>,
|
||||
|
@ -1281,7 +1233,6 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
|||
CD_PROP_BOOL,
|
||||
CD_PROP_BOOL,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
edge_access,
|
||||
make_array_read_attribute<bool>,
|
||||
|
@ -1294,7 +1245,6 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
|||
CD_PROP_FLOAT,
|
||||
CD_CREASE,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
edge_access,
|
||||
make_array_read_attribute<float>,
|
||||
|
@ -1308,7 +1258,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
|
|||
static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access);
|
||||
|
||||
return ComponentAttributeProviders(
|
||||
{&position, &id, &material_index, &shade_smooth, &sharp_edge, &normal, &crease},
|
||||
{&position, &id, &material_index, &shade_smooth, &sharp_edge, &crease},
|
||||
{&corner_custom_data,
|
||||
&vertex_groups,
|
||||
&point_custom_data,
|
||||
|
|
|
@ -142,7 +142,6 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
|
|||
CD_PROP_FLOAT3,
|
||||
CD_PROP_FLOAT3,
|
||||
BuiltinAttributeProvider::NonCreatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::NonDeletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float3>,
|
||||
|
@ -153,7 +152,6 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
|
|||
CD_PROP_FLOAT,
|
||||
CD_PROP_FLOAT,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<float>,
|
||||
|
@ -164,7 +162,6 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
|
|||
CD_PROP_INT32,
|
||||
CD_PROP_INT32,
|
||||
BuiltinAttributeProvider::Creatable,
|
||||
BuiltinAttributeProvider::Writable,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
point_access,
|
||||
make_array_read_attribute<int>,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_bit_vector.hh"
|
||||
#include "BLI_bounds.hh"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_endian_switch.h"
|
||||
|
@ -66,7 +65,6 @@
|
|||
|
||||
#include "BLO_read_write.h"
|
||||
|
||||
using blender::BitVector;
|
||||
using blender::float3;
|
||||
using blender::MutableSpan;
|
||||
using blender::Span;
|
||||
|
|
|
@ -316,7 +316,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
|
|||
BKE_mesh_vertex_normals_ensure(mesh) :
|
||||
nullptr;
|
||||
const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX));
|
||||
const blender::BitVector<> &facedot_tags = mesh->runtime->subsurf_face_dot_tags;
|
||||
const blender::BitSpan facedot_tags = mesh->runtime->subsurf_face_dot_tags;
|
||||
|
||||
if (index) {
|
||||
for (int i = 0; i < mesh->totpoly; i++, mp++) {
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
using blender::BitVector;
|
||||
using blender::float3;
|
||||
using blender::int2;
|
||||
using blender::MutableBitSpan;
|
||||
using blender::MutableSpan;
|
||||
using blender::short2;
|
||||
using blender::Span;
|
||||
|
@ -1238,7 +1239,7 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const Span<MLoop> mloop
|
|||
const Span<int2> edge_to_loops,
|
||||
const Span<int> loop_to_poly,
|
||||
const int *e2l_prev,
|
||||
BitVector<> &skip_loops,
|
||||
MutableBitSpan skip_loops,
|
||||
const int ml_curr_index,
|
||||
const int ml_prev_index,
|
||||
const int mp_curr_index)
|
||||
|
|
|
@ -91,7 +91,7 @@ void BKE_nlastrip_free(NlaStrip *strip, const bool do_id_user)
|
|||
MEM_freeN(strip);
|
||||
}
|
||||
|
||||
void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
|
||||
void BKE_nlatrack_free(NlaTrack *nlt, const bool do_id_user)
|
||||
{
|
||||
NlaStrip *strip, *stripn;
|
||||
|
||||
|
@ -107,12 +107,7 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
|
|||
}
|
||||
|
||||
/* free NLA track itself now */
|
||||
if (tracks) {
|
||||
BLI_freelinkN(tracks, nlt);
|
||||
}
|
||||
else {
|
||||
MEM_freeN(nlt);
|
||||
}
|
||||
MEM_freeN(nlt);
|
||||
}
|
||||
|
||||
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
|
||||
|
@ -127,7 +122,7 @@ void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
|
|||
/* free tracks one by one */
|
||||
for (nlt = tracks->first; nlt; nlt = nltn) {
|
||||
nltn = nlt->next;
|
||||
BKE_nlatrack_free(tracks, nlt, do_id_user);
|
||||
BKE_nlatrack_remove_and_free(tracks, nlt, do_id_user);
|
||||
}
|
||||
|
||||
/* clear the list's pointers to be safe */
|
||||
|
@ -514,6 +509,20 @@ void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
|
|||
}
|
||||
}
|
||||
|
||||
/* Removing ------------------------------------------ */
|
||||
|
||||
void BKE_nlatrack_remove(ListBase *tracks, struct NlaTrack *nlt)
|
||||
{
|
||||
BLI_assert(tracks);
|
||||
BLI_remlink(tracks, nlt);
|
||||
}
|
||||
|
||||
void BKE_nlatrack_remove_and_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user)
|
||||
{
|
||||
BKE_nlatrack_remove(tracks, nlt);
|
||||
BKE_nlatrack_free(nlt, do_id_user);
|
||||
}
|
||||
|
||||
/* *************************************************** */
|
||||
/* NLA Evaluation <-> Editing Stuff */
|
||||
|
||||
|
|
|
@ -91,5 +91,29 @@ TEST(nla_track, BKE_nlatrack_remove_strip)
|
|||
EXPECT_EQ(-1, BLI_findindex(&track.strips, &strip2));
|
||||
}
|
||||
|
||||
} // namespace blender::bke::tests
|
||||
TEST(nla_track, BKE_nlatrack_remove_and_free)
|
||||
{
|
||||
AnimData adt{};
|
||||
NlaTrack *track1;
|
||||
NlaTrack *track2;
|
||||
|
||||
// Add NLA tracks to the Animation Data.
|
||||
track1 = BKE_nlatrack_add(&adt, NULL, false);
|
||||
track2 = BKE_nlatrack_add(&adt, track1, false);
|
||||
|
||||
// ensure we have 2 tracks in the track.
|
||||
EXPECT_EQ(2, BLI_listbase_count(&adt.nla_tracks));
|
||||
|
||||
BKE_nlatrack_remove_and_free(&adt.nla_tracks, track2, false);
|
||||
EXPECT_EQ(1, BLI_listbase_count(&adt.nla_tracks));
|
||||
|
||||
// ensure the correct track was removed.
|
||||
EXPECT_EQ(-1, BLI_findindex(&adt.nla_tracks, track2));
|
||||
|
||||
// free the rest of the tracks, and ensure they are removed.
|
||||
BKE_nlatrack_remove_and_free(&adt.nla_tracks, track1, false);
|
||||
EXPECT_EQ(0, BLI_listbase_count(&adt.nla_tracks));
|
||||
EXPECT_EQ(-1, BLI_findindex(&adt.nla_tracks, track1));
|
||||
}
|
||||
|
||||
} // namespace blender::bke::tests
|
||||
|
|
|
@ -265,7 +265,7 @@ static DupliObject *make_dupli(const DupliContext *ctx,
|
|||
|
||||
/* Store geometry set data for attribute lookup in innermost to outermost
|
||||
* order, copying only non-null entries to save space. */
|
||||
const int max_instance = sizeof(dob->instance_data) / sizeof(void *);
|
||||
const int max_instance = ARRAY_SIZE(dob->instance_data);
|
||||
int next_instance = 0;
|
||||
if (geometry != nullptr) {
|
||||
dob->instance_idx[next_instance] = int(instance_index);
|
||||
|
@ -1821,7 +1821,7 @@ static bool find_geonode_attribute_rgba(const DupliObject *dupli,
|
|||
using namespace blender;
|
||||
|
||||
/* Loop over layers from innermost to outermost. */
|
||||
for (const int i : IndexRange(sizeof(dupli->instance_data) / sizeof(void *))) {
|
||||
for (const int i : IndexRange(ARRAY_SIZE(dupli->instance_data))) {
|
||||
/* Skip non-geonode layers. */
|
||||
if (dupli->instance_data[i] == nullptr) {
|
||||
continue;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "DNA_asset_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
|
@ -44,6 +46,7 @@ bUserAssetLibrary *BKE_preferences_asset_library_add(UserDef *userdef,
|
|||
if (path) {
|
||||
BLI_strncpy(library->path, path, sizeof(library->path));
|
||||
}
|
||||
library->import_method = ASSET_IMPORT_APPEND_REUSE;
|
||||
|
||||
return library;
|
||||
}
|
||||
|
|
|
@ -1704,7 +1704,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyO
|
|||
}
|
||||
}
|
||||
|
||||
/* Make transformed objects temporarily kinmatic
|
||||
/* Make transformed objects temporarily kinematic
|
||||
* so that they can be moved by the user during simulation. */
|
||||
if (is_selected && (G.moving & G_TRANSFORM_OBJ)) {
|
||||
RB_body_set_kinematic_state(rbo->shared->physics_object, true);
|
||||
|
|
|
@ -956,7 +956,9 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
|
|||
const int xy[2])
|
||||
{
|
||||
LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
|
||||
if (BLI_rcti_isect_pt_v(&area->totrct, xy)) {
|
||||
/* Test area's outer screen verts, not inner totrct. */
|
||||
if (xy[0] >= area->v1->vec.x && xy[0] <= area->v4->vec.x && xy[1] >= area->v1->vec.y &&
|
||||
xy[1] <= area->v2->vec.y) {
|
||||
if (ELEM(spacetype, SPACE_TYPE_ANY, area->spacetype)) {
|
||||
return area;
|
||||
}
|
||||
|
|
|
@ -352,7 +352,7 @@ struct StaticOrHeapIntStorage {
|
|||
|
||||
static void static_or_heap_storage_init(StaticOrHeapIntStorage *storage)
|
||||
{
|
||||
storage->static_storage_len = sizeof(storage->static_storage) / sizeof(*storage->static_storage);
|
||||
storage->static_storage_len = ARRAY_SIZE(storage->static_storage);
|
||||
storage->heap_storage = nullptr;
|
||||
storage->heap_storage_len = 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bli
|
||||
*
|
||||
* This file provides the basis for processing "indexed bits" (i.e. every bit has an index).
|
||||
* The main purpose of this file is to define how bits are indexed within a memory buffer.
|
||||
* For example, one has to define whether the first bit is the least or most significant bit and
|
||||
* how endianness affect the bit order.
|
||||
*
|
||||
* The order is defined as follows:
|
||||
* - Every indexed bit is part of an #BitInt. These ints are ordered by their address as usual.
|
||||
* - Within each #BitInt, the bits are ordered from least to most significant.
|
||||
*/
|
||||
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace blender::bits {
|
||||
|
||||
/** Using a large integer type is better because then it's easier to process many bits at once. */
|
||||
using BitInt = uint64_t;
|
||||
/** Number of bits that fit into #BitInt. */
|
||||
static constexpr int64_t BitsPerInt = int64_t(sizeof(BitInt) * 8);
|
||||
/** Shift amount to get from a bit index to an int index. Equivalent to `log(BitsPerInt, 2)`. */
|
||||
static constexpr int64_t BitToIntIndexShift = 3 + (sizeof(BitInt) >= 2) + (sizeof(BitInt) >= 4) +
|
||||
(sizeof(BitInt) >= 8);
|
||||
/** Bit mask containing a 1 for the last few bits that index a bit inside of an #BitInt. */
|
||||
static constexpr BitInt BitIndexMask = (BitInt(1) << BitToIntIndexShift) - 1;
|
||||
|
||||
inline BitInt mask_first_n_bits(const int64_t n)
|
||||
{
|
||||
BLI_assert(n >= 0);
|
||||
BLI_assert(n <= BitsPerInt);
|
||||
if (n == BitsPerInt) {
|
||||
return BitInt(-1);
|
||||
}
|
||||
return (BitInt(1) << n) - 1;
|
||||
}
|
||||
|
||||
inline BitInt mask_last_n_bits(const int64_t n)
|
||||
{
|
||||
return ~mask_first_n_bits(BitsPerInt - n);
|
||||
}
|
||||
|
||||
inline BitInt mask_range_bits(const int64_t start, const int64_t size)
|
||||
{
|
||||
BLI_assert(start >= 0);
|
||||
BLI_assert(size >= 0);
|
||||
const int64_t end = start + size;
|
||||
BLI_assert(end <= BitsPerInt);
|
||||
if (end == BitsPerInt) {
|
||||
return mask_last_n_bits(size);
|
||||
}
|
||||
return ((BitInt(1) << end) - 1) & ~((BitInt(1) << start) - 1);
|
||||
}
|
||||
|
||||
inline BitInt mask_single_bit(const int64_t bit_index)
|
||||
{
|
||||
BLI_assert(bit_index >= 0);
|
||||
BLI_assert(bit_index < BitsPerInt);
|
||||
return BitInt(1) << bit_index;
|
||||
}
|
||||
|
||||
inline BitInt *int_containing_bit(BitInt *data, const int64_t bit_index)
|
||||
{
|
||||
return data + (bit_index >> BitToIntIndexShift);
|
||||
}
|
||||
|
||||
inline const BitInt *int_containing_bit(const BitInt *data, const int64_t bit_index)
|
||||
{
|
||||
return data + (bit_index >> BitToIntIndexShift);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a read-only pointer to a specific bit. The value of the bit can be retrieved, but
|
||||
* not changed.
|
||||
*/
|
||||
class BitRef {
|
||||
private:
|
||||
/** Points to the exact integer that the bit is in. */
|
||||
const BitInt *int_;
|
||||
/** All zeros except for a single one at the bit that is referenced. */
|
||||
BitInt mask_;
|
||||
|
||||
friend class MutableBitRef;
|
||||
|
||||
public:
|
||||
BitRef() = default;
|
||||
|
||||
/**
|
||||
* Reference a specific bit in an array. Note that #data does *not* have to point to the
|
||||
* exact integer the bit is in.
|
||||
*/
|
||||
BitRef(const BitInt *data, const int64_t bit_index)
|
||||
{
|
||||
int_ = int_containing_bit(data, bit_index);
|
||||
mask_ = mask_single_bit(bit_index & BitIndexMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true when the bit is currently 1 and false otherwise.
|
||||
*/
|
||||
bool test() const
|
||||
{
|
||||
const BitInt value = *int_;
|
||||
const BitInt masked_value = value & mask_;
|
||||
return masked_value != 0;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return this->test();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Similar to #BitRef, but also allows changing the referenced bit.
|
||||
*/
|
||||
class MutableBitRef {
|
||||
private:
|
||||
/** Points to the integer that the bit is in. */
|
||||
BitInt *int_;
|
||||
/** All zeros except for a single one at the bit that is referenced. */
|
||||
BitInt mask_;
|
||||
|
||||
public:
|
||||
MutableBitRef() = default;
|
||||
|
||||
/**
|
||||
* Reference a specific bit in an array. Note that #data does *not* have to point to the
|
||||
* exact int the bit is in.
|
||||
*/
|
||||
MutableBitRef(BitInt *data, const int64_t bit_index)
|
||||
{
|
||||
int_ = int_containing_bit(data, bit_index);
|
||||
mask_ = mask_single_bit(bit_index & BitIndexMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Support implicitly casting to a read-only #BitRef.
|
||||
*/
|
||||
operator BitRef() const
|
||||
{
|
||||
BitRef bit_ref;
|
||||
bit_ref.int_ = int_;
|
||||
bit_ref.mask_ = mask_;
|
||||
return bit_ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true when the bit is currently 1 and false otherwise.
|
||||
*/
|
||||
bool test() const
|
||||
{
|
||||
const BitInt value = *int_;
|
||||
const BitInt masked_value = value & mask_;
|
||||
return masked_value != 0;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return this->test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the bit to a 1.
|
||||
*/
|
||||
void set()
|
||||
{
|
||||
*int_ |= mask_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the bit to a 0.
|
||||
*/
|
||||
void reset()
|
||||
{
|
||||
*int_ &= ~mask_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the bit to a 1 if #value is true and 0 otherwise. If the value is highly unpredictable
|
||||
* by the CPU branch predictor, it can be faster to use #set_branchless instead.
|
||||
*/
|
||||
void set(const bool value)
|
||||
{
|
||||
if (value) {
|
||||
this->set();
|
||||
}
|
||||
else {
|
||||
this->reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the same as #set, but does not use a branch. This is faster when the input value is
|
||||
* unpredictable for the CPU branch predictor (best case for this function is a uniform random
|
||||
* distribution with 50% probability for true and false). If the value is predictable, this is
|
||||
* likely slower than #set.
|
||||
*/
|
||||
void set_branchless(const bool value)
|
||||
{
|
||||
const BitInt value_int = BitInt(value);
|
||||
BLI_assert(ELEM(value_int, 0, 1));
|
||||
const BitInt old = *int_;
|
||||
*int_ =
|
||||
/* Unset bit. */
|
||||
(~mask_ & old)
|
||||
/* Optionally set it again. The -1 turns a 1 into `0x00...` and a 0 into `0xff...`. */
|
||||
| (mask_ & ~(value_int - 1));
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &stream, const BitRef &bit)
|
||||
{
|
||||
return stream << (bit ? "1" : "0");
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &stream, const MutableBitRef &bit)
|
||||
{
|
||||
return stream << BitRef(bit);
|
||||
}
|
||||
|
||||
} // namespace blender::bits
|
||||
|
||||
namespace blender {
|
||||
using bits::BitRef;
|
||||
using bits::MutableBitRef;
|
||||
} // namespace blender
|
|
@ -0,0 +1,290 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_bit_ref.hh"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_memory_utils.hh"
|
||||
|
||||
namespace blender::bits {
|
||||
|
||||
/** Base class for a const and non-const bit-iterator. */
|
||||
class BitIteratorBase {
|
||||
protected:
|
||||
const BitInt *data_;
|
||||
int64_t bit_index_;
|
||||
|
||||
public:
|
||||
BitIteratorBase(const BitInt *data, const int64_t bit_index) : data_(data), bit_index_(bit_index)
|
||||
{
|
||||
}
|
||||
|
||||
BitIteratorBase &operator++()
|
||||
{
|
||||
bit_index_++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator!=(const BitIteratorBase &a, const BitIteratorBase &b)
|
||||
{
|
||||
BLI_assert(a.data_ == b.data_);
|
||||
return a.bit_index_ != b.bit_index_;
|
||||
}
|
||||
};
|
||||
|
||||
/** Allows iterating over the bits in a memory buffer. */
|
||||
class BitIterator : public BitIteratorBase {
|
||||
public:
|
||||
BitIterator(const BitInt *data, const int64_t bit_index) : BitIteratorBase(data, bit_index)
|
||||
{
|
||||
}
|
||||
|
||||
BitRef operator*() const
|
||||
{
|
||||
return BitRef(data_, bit_index_);
|
||||
}
|
||||
};
|
||||
|
||||
/** Allows iterating over the bits in a memory buffer. */
|
||||
class MutableBitIterator : public BitIteratorBase {
|
||||
public:
|
||||
MutableBitIterator(BitInt *data, const int64_t bit_index) : BitIteratorBase(data, bit_index)
|
||||
{
|
||||
}
|
||||
|
||||
MutableBitRef operator*() const
|
||||
{
|
||||
return MutableBitRef(const_cast<BitInt *>(data_), bit_index_);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Similar to #Span, but references a range of bits instead of normal C++ types (which must be at
|
||||
* least one byte large). Use #MutableBitSpan if the values are supposed to be modified.
|
||||
*
|
||||
* The beginning and end of a #BitSpan does *not* have to be at byte/int boundaries. It can start
|
||||
* and end at any bit.
|
||||
*/
|
||||
class BitSpan {
|
||||
private:
|
||||
/** Base pointer to the integers containing the bits. The actual bit span might start at a much
|
||||
* higher address when `bit_range_.start()` is large. */
|
||||
const BitInt *data_ = nullptr;
|
||||
/** The range of referenced bits. */
|
||||
IndexRange bit_range_ = {0, 0};
|
||||
|
||||
public:
|
||||
/** Construct an empty span. */
|
||||
BitSpan() = default;
|
||||
|
||||
BitSpan(const BitInt *data, const int64_t size_in_bits) : data_(data), bit_range_(size_in_bits)
|
||||
{
|
||||
}
|
||||
|
||||
BitSpan(const BitInt *data, const IndexRange bit_range) : data_(data), bit_range_(bit_range)
|
||||
{
|
||||
}
|
||||
|
||||
/** Number of bits referenced by the span. */
|
||||
int64_t size() const
|
||||
{
|
||||
return bit_range_.size();
|
||||
}
|
||||
|
||||
bool is_empty() const
|
||||
{
|
||||
return bit_range_.is_empty();
|
||||
}
|
||||
|
||||
IndexRange index_range() const
|
||||
{
|
||||
return IndexRange(bit_range_.size());
|
||||
}
|
||||
|
||||
BitRef operator[](const int64_t index) const
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
BLI_assert(index < bit_range_.size());
|
||||
return {data_, bit_range_.start() + index};
|
||||
}
|
||||
|
||||
BitSpan slice(const IndexRange range) const
|
||||
{
|
||||
return {data_, bit_range_.slice(range)};
|
||||
}
|
||||
|
||||
const BitInt *data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const IndexRange &bit_range() const
|
||||
{
|
||||
return bit_range_;
|
||||
}
|
||||
|
||||
BitIterator begin() const
|
||||
{
|
||||
return {data_, bit_range_.start()};
|
||||
}
|
||||
|
||||
BitIterator end() const
|
||||
{
|
||||
return {data_, bit_range_.one_after_last()};
|
||||
}
|
||||
};
|
||||
|
||||
/** Same as #BitSpan, but also allows modifying the referenced bits. */
|
||||
class MutableBitSpan {
|
||||
private:
|
||||
BitInt *data_ = nullptr;
|
||||
IndexRange bit_range_ = {0, 0};
|
||||
|
||||
public:
|
||||
MutableBitSpan() = default;
|
||||
|
||||
MutableBitSpan(BitInt *data, const int64_t size) : data_(data), bit_range_(size)
|
||||
{
|
||||
}
|
||||
|
||||
MutableBitSpan(BitInt *data, const IndexRange bit_range) : data_(data), bit_range_(bit_range)
|
||||
{
|
||||
}
|
||||
|
||||
int64_t size() const
|
||||
{
|
||||
return bit_range_.size();
|
||||
}
|
||||
|
||||
bool is_empty() const
|
||||
{
|
||||
return bit_range_.is_empty();
|
||||
}
|
||||
|
||||
IndexRange index_range() const
|
||||
{
|
||||
return IndexRange(bit_range_.size());
|
||||
}
|
||||
|
||||
MutableBitRef operator[](const int64_t index) const
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
BLI_assert(index < bit_range_.size());
|
||||
return {data_, bit_range_.start() + index};
|
||||
}
|
||||
|
||||
MutableBitSpan slice(const IndexRange range) const
|
||||
{
|
||||
return {data_, bit_range_.slice(range)};
|
||||
}
|
||||
|
||||
BitInt *data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const IndexRange &bit_range() const
|
||||
{
|
||||
return bit_range_;
|
||||
}
|
||||
|
||||
MutableBitIterator begin() const
|
||||
{
|
||||
return {data_, bit_range_.start()};
|
||||
}
|
||||
|
||||
MutableBitIterator end() const
|
||||
{
|
||||
return {data_, bit_range_.one_after_last()};
|
||||
}
|
||||
|
||||
operator BitSpan() const
|
||||
{
|
||||
return {data_, bit_range_};
|
||||
}
|
||||
|
||||
/** Sets all referenced bits to 1. */
|
||||
void set_all()
|
||||
{
|
||||
const AlignedIndexRanges ranges = split_index_range_by_alignment(bit_range_, BitsPerInt);
|
||||
{
|
||||
BitInt &first_int = *int_containing_bit(data_, bit_range_.start());
|
||||
const BitInt first_int_mask = mask_range_bits(ranges.prefix.start() & BitIndexMask,
|
||||
ranges.prefix.size());
|
||||
first_int |= first_int_mask;
|
||||
}
|
||||
{
|
||||
BitInt *start = int_containing_bit(data_, ranges.aligned.start());
|
||||
const int64_t ints_to_fill = ranges.aligned.size() / BitsPerInt;
|
||||
constexpr BitInt fill_value = BitInt(-1);
|
||||
initialized_fill_n(start, ints_to_fill, fill_value);
|
||||
}
|
||||
{
|
||||
BitInt &last_int = *int_containing_bit(data_, bit_range_.one_after_last() - 1);
|
||||
const BitInt last_int_mask = mask_first_n_bits(ranges.suffix.size());
|
||||
last_int |= last_int_mask;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets all referenced bits to 0. */
|
||||
void reset_all()
|
||||
{
|
||||
const AlignedIndexRanges ranges = split_index_range_by_alignment(bit_range_, BitsPerInt);
|
||||
{
|
||||
BitInt &first_int = *int_containing_bit(data_, bit_range_.start());
|
||||
const BitInt first_int_mask = mask_range_bits(ranges.prefix.start() & BitIndexMask,
|
||||
ranges.prefix.size());
|
||||
first_int &= ~first_int_mask;
|
||||
}
|
||||
{
|
||||
BitInt *start = int_containing_bit(data_, ranges.aligned.start());
|
||||
const int64_t ints_to_fill = ranges.aligned.size() / BitsPerInt;
|
||||
constexpr BitInt fill_value = 0;
|
||||
initialized_fill_n(start, ints_to_fill, fill_value);
|
||||
}
|
||||
{
|
||||
BitInt &last_int = *int_containing_bit(data_, bit_range_.one_after_last() - 1);
|
||||
const BitInt last_int_mask = mask_first_n_bits(ranges.suffix.size());
|
||||
last_int &= ~last_int_mask;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets all referenced bits to either 0 or 1. */
|
||||
void set_all(const bool value)
|
||||
{
|
||||
if (value) {
|
||||
this->set_all();
|
||||
}
|
||||
else {
|
||||
this->reset_all();
|
||||
}
|
||||
}
|
||||
|
||||
/** Same as #set_all to mirror #MutableSpan. */
|
||||
void fill(const bool value)
|
||||
{
|
||||
this->set_all(value);
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &stream, const BitSpan &span)
|
||||
{
|
||||
stream << "(Size: " << span.size() << ", ";
|
||||
for (const BitRef bit : span) {
|
||||
stream << bit;
|
||||
}
|
||||
stream << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &stream, const MutableBitSpan &span)
|
||||
{
|
||||
return stream << BitSpan(span);
|
||||
}
|
||||
|
||||
} // namespace blender::bits
|
||||
|
||||
namespace blender {
|
||||
using bits::BitSpan;
|
||||
using bits::MutableBitSpan;
|
||||
} // namespace blender
|
|
@ -38,142 +38,11 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "BLI_allocator.hh"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_memory_utils.hh"
|
||||
#include "BLI_bit_span.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
namespace blender::bits {
|
||||
|
||||
/**
|
||||
* Using a large integer type is better because then it's easier to process many bits at once.
|
||||
*/
|
||||
using IntType = uint64_t;
|
||||
static constexpr int64_t BitsPerInt = int64_t(sizeof(IntType) * 8);
|
||||
static constexpr int64_t BitToIntIndexShift = 3 + (sizeof(IntType) >= 2) + (sizeof(IntType) >= 4) +
|
||||
(sizeof(IntType) >= 8);
|
||||
static constexpr IntType BitIndexMask = (IntType(1) << BitToIntIndexShift) - 1;
|
||||
|
||||
/**
|
||||
* This is a read-only pointer to a specific bit. The value of the bit can be retrieved, but
|
||||
* not changed.
|
||||
*/
|
||||
class BitRef {
|
||||
private:
|
||||
/** Points to the integer that the bit is in. */
|
||||
const IntType *ptr_;
|
||||
/** All zeros except for a single one at the bit that is referenced. */
|
||||
IntType mask_;
|
||||
|
||||
friend class MutableBitRef;
|
||||
|
||||
public:
|
||||
BitRef() = default;
|
||||
|
||||
/**
|
||||
* Reference a specific bit in an array. Note that #ptr does *not* have to point to the
|
||||
* exact integer the bit is in.
|
||||
*/
|
||||
BitRef(const IntType *ptr, const int64_t bit_index)
|
||||
{
|
||||
ptr_ = ptr + (bit_index >> BitToIntIndexShift);
|
||||
mask_ = IntType(1) << (bit_index & BitIndexMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true when the bit is currently 1 and false otherwise.
|
||||
*/
|
||||
bool test() const
|
||||
{
|
||||
const IntType value = *ptr_;
|
||||
const IntType masked_value = value & mask_;
|
||||
return masked_value != 0;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return this->test();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Similar to #BitRef, but also allows changing the referenced bit.
|
||||
*/
|
||||
class MutableBitRef {
|
||||
private:
|
||||
/** Points to the integer that the bit is in. */
|
||||
IntType *ptr_;
|
||||
/** All zeros except for a single one at the bit that is referenced. */
|
||||
IntType mask_;
|
||||
|
||||
public:
|
||||
MutableBitRef() = default;
|
||||
|
||||
/**
|
||||
* Reference a specific bit in an array. Note that #ptr does *not* have to point to the
|
||||
* exact int the bit is in.
|
||||
*/
|
||||
MutableBitRef(IntType *ptr, const int64_t bit_index)
|
||||
{
|
||||
ptr_ = ptr + (bit_index >> BitToIntIndexShift);
|
||||
mask_ = IntType(1) << IntType(bit_index & BitIndexMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Support implicitly casting to a read-only #BitRef.
|
||||
*/
|
||||
operator BitRef() const
|
||||
{
|
||||
BitRef bit_ref;
|
||||
bit_ref.ptr_ = ptr_;
|
||||
bit_ref.mask_ = mask_;
|
||||
return bit_ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true when the bit is currently 1 and false otherwise.
|
||||
*/
|
||||
bool test() const
|
||||
{
|
||||
const IntType value = *ptr_;
|
||||
const IntType masked_value = value & mask_;
|
||||
return masked_value != 0;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return this->test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the bit to a 1.
|
||||
*/
|
||||
void set()
|
||||
{
|
||||
*ptr_ |= mask_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the bit to a 0.
|
||||
*/
|
||||
void reset()
|
||||
{
|
||||
*ptr_ &= ~mask_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the bit to a 1 if #value is true and 0 otherwise.
|
||||
*/
|
||||
void set(const bool value)
|
||||
{
|
||||
if (value) {
|
||||
this->set();
|
||||
}
|
||||
else {
|
||||
this->reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
/**
|
||||
* Number of bits that can be stored in the vector without doing an allocation.
|
||||
|
@ -193,13 +62,13 @@ class BitVector {
|
|||
|
||||
static constexpr int64_t IntsInInlineBuffer = required_ints_for_bits(InlineBufferCapacity);
|
||||
static constexpr int64_t BitsInInlineBuffer = IntsInInlineBuffer * BitsPerInt;
|
||||
static constexpr int64_t AllocationAlignment = alignof(IntType);
|
||||
static constexpr int64_t AllocationAlignment = alignof(BitInt);
|
||||
|
||||
/**
|
||||
* Points to the first integer used by the vector. It might point to the memory in the inline
|
||||
* buffer.
|
||||
*/
|
||||
IntType *data_;
|
||||
BitInt *data_;
|
||||
|
||||
/** Current size of the vector in bits. */
|
||||
int64_t size_in_bits_;
|
||||
|
@ -211,7 +80,7 @@ class BitVector {
|
|||
BLI_NO_UNIQUE_ADDRESS Allocator allocator_;
|
||||
|
||||
/** Contains the bits as long as the vector is small enough. */
|
||||
BLI_NO_UNIQUE_ADDRESS TypedBuffer<IntType, IntsInInlineBuffer> inline_buffer_;
|
||||
BLI_NO_UNIQUE_ADDRESS TypedBuffer<BitInt, IntsInInlineBuffer> inline_buffer_;
|
||||
|
||||
public:
|
||||
BitVector(Allocator allocator = {}) noexcept : allocator_(allocator)
|
||||
|
@ -219,7 +88,7 @@ class BitVector {
|
|||
data_ = inline_buffer_;
|
||||
size_in_bits_ = 0;
|
||||
capacity_in_bits_ = BitsInInlineBuffer;
|
||||
uninitialized_fill_n(data_, IntsInInlineBuffer, IntType(0));
|
||||
uninitialized_fill_n(data_, IntsInInlineBuffer, BitInt(0));
|
||||
}
|
||||
|
||||
BitVector(NoExceptConstructor, Allocator allocator = {}) noexcept : BitVector(allocator)
|
||||
|
@ -236,8 +105,8 @@ class BitVector {
|
|||
}
|
||||
else {
|
||||
/* Allocate a new array because the inline buffer is too small. */
|
||||
data_ = static_cast<IntType *>(
|
||||
allocator_.allocate(ints_to_copy * sizeof(IntType), AllocationAlignment, __func__));
|
||||
data_ = static_cast<BitInt *>(
|
||||
allocator_.allocate(ints_to_copy * sizeof(BitInt), AllocationAlignment, __func__));
|
||||
capacity_in_bits_ = ints_to_copy * BitsPerInt;
|
||||
}
|
||||
size_in_bits_ = other.size_in_bits_;
|
||||
|
@ -303,6 +172,16 @@ class BitVector {
|
|||
return move_assign_container(*this, std::move(other));
|
||||
}
|
||||
|
||||
operator BitSpan() const
|
||||
{
|
||||
return {data_, IndexRange(size_in_bits_)};
|
||||
}
|
||||
|
||||
operator MutableBitSpan()
|
||||
{
|
||||
return {data_, IndexRange(size_in_bits_)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of bits in the bit vector.
|
||||
*/
|
||||
|
@ -352,80 +231,24 @@ class BitVector {
|
|||
size_in_bits_++;
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
private:
|
||||
const BitVector *vector_;
|
||||
int64_t index_;
|
||||
|
||||
public:
|
||||
Iterator(const BitVector &vector, const int64_t index) : vector_(&vector), index_(index)
|
||||
{
|
||||
}
|
||||
|
||||
Iterator &operator++()
|
||||
{
|
||||
index_++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator!=(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
BLI_assert(a.vector_ == b.vector_);
|
||||
return a.index_ != b.index_;
|
||||
}
|
||||
|
||||
BitRef operator*() const
|
||||
{
|
||||
return (*vector_)[index_];
|
||||
}
|
||||
};
|
||||
|
||||
class MutableIterator {
|
||||
private:
|
||||
BitVector *vector_;
|
||||
int64_t index_;
|
||||
|
||||
public:
|
||||
MutableIterator(BitVector &vector, const int64_t index) : vector_(&vector), index_(index)
|
||||
{
|
||||
}
|
||||
|
||||
MutableIterator &operator++()
|
||||
{
|
||||
index_++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator!=(const MutableIterator &a, const MutableIterator &b)
|
||||
{
|
||||
BLI_assert(a.vector_ == b.vector_);
|
||||
return a.index_ != b.index_;
|
||||
}
|
||||
|
||||
MutableBitRef operator*() const
|
||||
{
|
||||
return (*vector_)[index_];
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() const
|
||||
BitIterator begin() const
|
||||
{
|
||||
return {*this, 0};
|
||||
return {data_, 0};
|
||||
}
|
||||
|
||||
Iterator end() const
|
||||
BitIterator end() const
|
||||
{
|
||||
return {*this, size_in_bits_};
|
||||
return {data_, size_in_bits_};
|
||||
}
|
||||
|
||||
MutableIterator begin()
|
||||
MutableBitIterator begin()
|
||||
{
|
||||
return {*this, 0};
|
||||
return {data_, 0};
|
||||
}
|
||||
|
||||
MutableIterator end()
|
||||
MutableBitIterator end()
|
||||
{
|
||||
return {*this, size_in_bits_};
|
||||
return {data_, size_in_bits_};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -441,31 +264,8 @@ class BitVector {
|
|||
}
|
||||
size_in_bits_ = new_size_in_bits;
|
||||
if (old_size_in_bits < new_size_in_bits) {
|
||||
this->fill_range(IndexRange(old_size_in_bits, new_size_in_bits - old_size_in_bits), value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set #value for every element in #range.
|
||||
*/
|
||||
void fill_range(const IndexRange range, const bool value)
|
||||
{
|
||||
const AlignedIndexRanges aligned_ranges = split_index_range_by_alignment(range, BitsPerInt);
|
||||
|
||||
/* Fill first few bits. */
|
||||
for (const int64_t i : aligned_ranges.prefix) {
|
||||
(*this)[i].set(value);
|
||||
}
|
||||
|
||||
/* Fill entire ints at once. */
|
||||
const int64_t start_fill_int_index = aligned_ranges.aligned.start() / BitsPerInt;
|
||||
const int64_t ints_to_fill = aligned_ranges.aligned.size() / BitsPerInt;
|
||||
const IntType fill_value = value ? IntType(-1) : IntType(0);
|
||||
initialized_fill_n(data_ + start_fill_int_index, ints_to_fill, fill_value);
|
||||
|
||||
/* Fill bits in the end that don't cover a full int. */
|
||||
for (const int64_t i : aligned_ranges.suffix) {
|
||||
(*this)[i].set(value);
|
||||
MutableBitSpan(data_, IndexRange(old_size_in_bits, new_size_in_bits - old_size_in_bits))
|
||||
.set_all(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,7 +274,7 @@ class BitVector {
|
|||
*/
|
||||
void fill(const bool value)
|
||||
{
|
||||
this->fill_range(IndexRange(0, size_in_bits_), value);
|
||||
MutableBitSpan(data_, size_in_bits_).set_all(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -517,7 +317,7 @@ class BitVector {
|
|||
}
|
||||
|
||||
BLI_NOINLINE void realloc_to_at_least(const int64_t min_capacity_in_bits,
|
||||
const IntType initial_value_for_new_ints = 0x00)
|
||||
const BitInt initial_value_for_new_ints = 0)
|
||||
{
|
||||
if (capacity_in_bits_ >= min_capacity_in_bits) {
|
||||
return;
|
||||
|
@ -531,8 +331,8 @@ class BitVector {
|
|||
const int64_t new_capacity_in_ints = std::max(min_capacity_in_ints, min_new_capacity_in_ints);
|
||||
const int64_t ints_to_copy = this->used_ints_amount();
|
||||
|
||||
IntType *new_data = static_cast<IntType *>(allocator_.allocate(
|
||||
new_capacity_in_ints * sizeof(IntType), AllocationAlignment, __func__));
|
||||
BitInt *new_data = static_cast<BitInt *>(
|
||||
allocator_.allocate(new_capacity_in_ints * sizeof(BitInt), AllocationAlignment, __func__));
|
||||
uninitialized_copy_n(data_, ints_to_copy, new_data);
|
||||
/* Always initialize new capacity even if it isn't used yet. That's necessary to avoid warnings
|
||||
* caused by using uninitialized memory. This happens when e.g. setting a clearing a bit in an
|
||||
|
@ -562,7 +362,5 @@ class BitVector {
|
|||
} // namespace blender::bits
|
||||
|
||||
namespace blender {
|
||||
using bits::BitRef;
|
||||
using bits::BitVector;
|
||||
using bits::MutableBitRef;
|
||||
} // namespace blender
|
||||
|
|
|
@ -806,6 +806,10 @@ extern bool BLI_memory_is_zero(const void *arr, size_t arr_size);
|
|||
{ \
|
||||
return a = (_enum_type)(uint64_t(a) & uint64_t(b)); \
|
||||
} \
|
||||
inline _enum_type &operator^=(_enum_type &a, _enum_type b) \
|
||||
{ \
|
||||
return a = (_enum_type)(uint64_t(a) ^ uint64_t(b)); \
|
||||
} \
|
||||
} /* extern "C++" */
|
||||
|
||||
#else
|
||||
|
|
|
@ -281,10 +281,10 @@ set(SRC
|
|||
BLI_math_solvers.h
|
||||
BLI_math_statistics.h
|
||||
BLI_math_time.h
|
||||
BLI_math_vector_mpq_types.hh
|
||||
BLI_math_vector_types.hh
|
||||
BLI_math_vector.h
|
||||
BLI_math_vector.hh
|
||||
BLI_math_vector_mpq_types.hh
|
||||
BLI_math_vector_types.hh
|
||||
BLI_memarena.h
|
||||
BLI_memblock.h
|
||||
BLI_memiter.h
|
||||
|
@ -457,6 +457,8 @@ if(WITH_GTESTS)
|
|||
tests/BLI_array_store_test.cc
|
||||
tests/BLI_array_test.cc
|
||||
tests/BLI_array_utils_test.cc
|
||||
tests/BLI_bit_ref_test.cc
|
||||
tests/BLI_bit_span_test.cc
|
||||
tests/BLI_bit_vector_test.cc
|
||||
tests/BLI_bitmap_test.cc
|
||||
tests/BLI_bounds_test.cc
|
||||
|
@ -490,13 +492,13 @@ if(WITH_GTESTS)
|
|||
tests/BLI_math_bits_test.cc
|
||||
tests/BLI_math_color_test.cc
|
||||
tests/BLI_math_geom_test.cc
|
||||
tests/BLI_math_matrix_types_test.cc
|
||||
tests/BLI_math_matrix_test.cc
|
||||
tests/BLI_math_matrix_types_test.cc
|
||||
tests/BLI_math_rotation_test.cc
|
||||
tests/BLI_math_solvers_test.cc
|
||||
tests/BLI_math_time_test.cc
|
||||
tests/BLI_math_vector_types_test.cc
|
||||
tests/BLI_math_vector_test.cc
|
||||
tests/BLI_math_vector_types_test.cc
|
||||
tests/BLI_memiter_test.cc
|
||||
tests/BLI_memory_utils_test.cc
|
||||
tests/BLI_mesh_boolean_test.cc
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "BLI_bit_ref.hh"
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
namespace blender::bits::tests {
|
||||
|
||||
TEST(bit_ref, MaskFirstNBits)
|
||||
{
|
||||
EXPECT_EQ(mask_first_n_bits(0), 0);
|
||||
EXPECT_EQ(mask_first_n_bits(1),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0001);
|
||||
EXPECT_EQ(mask_first_n_bits(5),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0001'1111);
|
||||
EXPECT_EQ(mask_first_n_bits(63),
|
||||
0b0111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111);
|
||||
EXPECT_EQ(mask_first_n_bits(64),
|
||||
0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111);
|
||||
}
|
||||
|
||||
TEST(bit_ref, MaskLastNBits)
|
||||
{
|
||||
EXPECT_EQ(mask_last_n_bits(0),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
EXPECT_EQ(mask_last_n_bits(1),
|
||||
0b1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
EXPECT_EQ(mask_last_n_bits(5),
|
||||
0b1111'1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
EXPECT_EQ(mask_last_n_bits(63),
|
||||
0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1110);
|
||||
EXPECT_EQ(mask_last_n_bits(64),
|
||||
0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111);
|
||||
}
|
||||
|
||||
TEST(bit_ref, MaskSingleBit)
|
||||
{
|
||||
EXPECT_EQ(mask_single_bit(0), 1);
|
||||
EXPECT_EQ(mask_single_bit(1),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0010);
|
||||
EXPECT_EQ(mask_single_bit(5),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0010'0000);
|
||||
EXPECT_EQ(mask_single_bit(63),
|
||||
0b1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
}
|
||||
|
||||
TEST(bit_ref, IntContainingBit)
|
||||
{
|
||||
std::array<uint64_t, 5> array;
|
||||
uint64_t *data = array.data();
|
||||
EXPECT_EQ(int_containing_bit(data, 0), data);
|
||||
EXPECT_EQ(int_containing_bit(data, 1), data);
|
||||
EXPECT_EQ(int_containing_bit(data, 63), data);
|
||||
EXPECT_EQ(int_containing_bit(data, 64), data + 1);
|
||||
EXPECT_EQ(int_containing_bit(data, 65), data + 1);
|
||||
EXPECT_EQ(int_containing_bit(data, 100), data + 1);
|
||||
EXPECT_EQ(int_containing_bit(data, 127), data + 1);
|
||||
EXPECT_EQ(int_containing_bit(data, 128), data + 2);
|
||||
const uint64_t *data_const = data;
|
||||
EXPECT_EQ(int_containing_bit(data_const, 0), data_const);
|
||||
EXPECT_EQ(int_containing_bit(data_const, 1), data_const);
|
||||
EXPECT_EQ(int_containing_bit(data_const, 63), data_const);
|
||||
EXPECT_EQ(int_containing_bit(data_const, 64), data_const + 1);
|
||||
EXPECT_EQ(int_containing_bit(data_const, 65), data_const + 1);
|
||||
EXPECT_EQ(int_containing_bit(data_const, 100), data_const + 1);
|
||||
EXPECT_EQ(int_containing_bit(data_const, 127), data_const + 1);
|
||||
EXPECT_EQ(int_containing_bit(data_const, 128), data_const + 2);
|
||||
}
|
||||
|
||||
TEST(bit_ref, Test)
|
||||
{
|
||||
uint64_t data = (1 << 3) | (1 << 7);
|
||||
EXPECT_FALSE(BitRef(&data, 0).test());
|
||||
EXPECT_FALSE(BitRef(&data, 1).test());
|
||||
EXPECT_FALSE(BitRef(&data, 2).test());
|
||||
EXPECT_TRUE(BitRef(&data, 3).test());
|
||||
EXPECT_FALSE(BitRef(&data, 4));
|
||||
EXPECT_FALSE(BitRef(&data, 5));
|
||||
EXPECT_FALSE(BitRef(&data, 6));
|
||||
EXPECT_TRUE(BitRef(&data, 7));
|
||||
|
||||
EXPECT_FALSE(MutableBitRef(&data, 0).test());
|
||||
EXPECT_FALSE(MutableBitRef(&data, 1).test());
|
||||
EXPECT_FALSE(MutableBitRef(&data, 2).test());
|
||||
EXPECT_TRUE(MutableBitRef(&data, 3).test());
|
||||
EXPECT_FALSE(MutableBitRef(&data, 4));
|
||||
EXPECT_FALSE(MutableBitRef(&data, 5));
|
||||
EXPECT_FALSE(MutableBitRef(&data, 6));
|
||||
EXPECT_TRUE(MutableBitRef(&data, 7));
|
||||
}
|
||||
|
||||
TEST(bit_ref, Set)
|
||||
{
|
||||
uint64_t data = 0;
|
||||
MutableBitRef(&data, 0).set();
|
||||
MutableBitRef(&data, 1).set();
|
||||
MutableBitRef(&data, 1).set();
|
||||
MutableBitRef(&data, 4).set();
|
||||
EXPECT_EQ(data, (1 << 0) | (1 << 1) | (1 << 4));
|
||||
MutableBitRef(&data, 5).set(true);
|
||||
MutableBitRef(&data, 1).set(false);
|
||||
EXPECT_EQ(data, (1 << 0) | (1 << 4) | (1 << 5));
|
||||
}
|
||||
|
||||
TEST(bit_ref, Reset)
|
||||
{
|
||||
uint64_t data = -1;
|
||||
MutableBitRef(&data, 0).reset();
|
||||
MutableBitRef(&data, 2).reset();
|
||||
EXPECT_EQ(data, uint64_t(-1) & ~(1 << 0) & ~(1 << 2));
|
||||
}
|
||||
|
||||
TEST(bit_ref, SetBranchless)
|
||||
{
|
||||
uint64_t data = 0;
|
||||
MutableBitRef(&data, 0).set_branchless(true);
|
||||
EXPECT_EQ(data, 1);
|
||||
MutableBitRef(&data, 0).set_branchless(false);
|
||||
EXPECT_EQ(data, 0);
|
||||
MutableBitRef(&data, 3).set_branchless(false);
|
||||
MutableBitRef(&data, 4).set_branchless(true);
|
||||
EXPECT_EQ(data, 16);
|
||||
MutableBitRef(&data, 3).set_branchless(true);
|
||||
MutableBitRef(&data, 4).set_branchless(true);
|
||||
EXPECT_EQ(data, 24);
|
||||
}
|
||||
|
||||
TEST(bit_ref, Cast)
|
||||
{
|
||||
uint64_t data = 0;
|
||||
MutableBitRef mutable_ref(&data, 3);
|
||||
BitRef ref = mutable_ref;
|
||||
EXPECT_FALSE(ref);
|
||||
mutable_ref.set();
|
||||
EXPECT_TRUE(ref);
|
||||
}
|
||||
|
||||
TEST(bit_ref, MaskRangeBits)
|
||||
{
|
||||
EXPECT_EQ(mask_range_bits(0, 0),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
EXPECT_EQ(mask_range_bits(0, 1),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0001);
|
||||
EXPECT_EQ(mask_range_bits(0, 5),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0001'1111);
|
||||
EXPECT_EQ(mask_range_bits(64, 0),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
EXPECT_EQ(mask_range_bits(63, 1),
|
||||
0b1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
EXPECT_EQ(mask_range_bits(59, 5),
|
||||
0b1111'1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
EXPECT_EQ(mask_range_bits(8, 3),
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0111'0000'0000);
|
||||
EXPECT_EQ(mask_range_bits(0, 64),
|
||||
0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111);
|
||||
}
|
||||
|
||||
} // namespace blender::bits::tests
|
|
@ -0,0 +1,139 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "BLI_bit_span.hh"
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
namespace blender::bits::tests {
|
||||
|
||||
TEST(bit_span, DefaultConstructor)
|
||||
{
|
||||
{
|
||||
char buffer[sizeof(BitSpan)];
|
||||
memset(buffer, 0xff, sizeof(BitSpan));
|
||||
BitSpan &span = *new (buffer) BitSpan();
|
||||
EXPECT_TRUE(span.is_empty());
|
||||
EXPECT_EQ(span.size(), 0);
|
||||
}
|
||||
{
|
||||
char buffer[sizeof(MutableBitSpan)];
|
||||
memset(buffer, 0xff, sizeof(MutableBitSpan));
|
||||
MutableBitSpan &span = *new (buffer) MutableBitSpan();
|
||||
EXPECT_TRUE(span.is_empty());
|
||||
EXPECT_EQ(span.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bit_span, Iteration)
|
||||
{
|
||||
uint64_t data = (1 << 2) | (1 << 3);
|
||||
const BitSpan span(&data, 30);
|
||||
EXPECT_EQ(span.size(), 30);
|
||||
int index = 0;
|
||||
for (const BitRef bit : span) {
|
||||
EXPECT_EQ(bit.test(), ELEM(index, 2, 3));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bit_span, MutableIteration)
|
||||
{
|
||||
uint64_t data = 0;
|
||||
MutableBitSpan span(&data, 40);
|
||||
EXPECT_EQ(span.size(), 40);
|
||||
int index = 0;
|
||||
for (MutableBitRef bit : span) {
|
||||
bit.set(index % 4 == 0);
|
||||
index++;
|
||||
}
|
||||
EXPECT_EQ(data,
|
||||
0b0000'0000'0000'0000'0000'0000'0001'0001'0001'0001'0001'0001'0001'0001'0001'0001);
|
||||
}
|
||||
|
||||
TEST(bit_span, SubscriptOperator)
|
||||
{
|
||||
uint64_t data[2] = {0, 0};
|
||||
MutableBitSpan mutable_span(data, 128);
|
||||
BitSpan span = mutable_span;
|
||||
|
||||
EXPECT_EQ(mutable_span.data(), data);
|
||||
EXPECT_EQ(mutable_span.bit_range(), IndexRange(128));
|
||||
EXPECT_EQ(span.data(), data);
|
||||
EXPECT_EQ(span.bit_range(), IndexRange(128));
|
||||
|
||||
EXPECT_FALSE(mutable_span[5].test());
|
||||
EXPECT_FALSE(span[5].test());
|
||||
mutable_span[5].set(5);
|
||||
EXPECT_TRUE(mutable_span[5].test());
|
||||
EXPECT_TRUE(span[5].test());
|
||||
|
||||
EXPECT_FALSE(mutable_span[120].test());
|
||||
EXPECT_FALSE(span[120].test());
|
||||
mutable_span[120].set(120);
|
||||
EXPECT_TRUE(mutable_span[120].test());
|
||||
EXPECT_TRUE(span[120].test());
|
||||
|
||||
EXPECT_EQ(data[0],
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0010'0000);
|
||||
EXPECT_EQ(data[1],
|
||||
0b0000'0001'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
|
||||
}
|
||||
|
||||
TEST(bit_span, RangeConstructor)
|
||||
{
|
||||
uint64_t data = 0;
|
||||
MutableBitSpan mutable_span(&data, IndexRange(4, 3));
|
||||
BitSpan span = mutable_span;
|
||||
|
||||
EXPECT_FALSE(mutable_span[1].test());
|
||||
EXPECT_FALSE(span[1].test());
|
||||
mutable_span[0].set(true);
|
||||
mutable_span[1].set(true);
|
||||
mutable_span[2].set(true);
|
||||
mutable_span[0].set(false);
|
||||
mutable_span[2].set(false);
|
||||
EXPECT_TRUE(mutable_span[1].test());
|
||||
EXPECT_TRUE(span[1].test());
|
||||
|
||||
EXPECT_EQ(data,
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0010'0000);
|
||||
}
|
||||
|
||||
TEST(bit_span, Set)
|
||||
{
|
||||
uint64_t data = 0;
|
||||
MutableBitSpan(&data, 64).set_all(true);
|
||||
EXPECT_EQ(data, uint64_t(-1));
|
||||
MutableBitSpan(&data, 64).set_all(false);
|
||||
EXPECT_EQ(data, uint64_t(0));
|
||||
|
||||
MutableBitSpan(&data, IndexRange(4, 8)).set_all(true);
|
||||
EXPECT_EQ(data,
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111'1111'0000);
|
||||
MutableBitSpan(&data, IndexRange(8, 30)).set_all(false);
|
||||
|
||||
EXPECT_EQ(data,
|
||||
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111'0000);
|
||||
}
|
||||
|
||||
TEST(bit_span, SetSliced)
|
||||
{
|
||||
std::array<uint64_t, 10> data;
|
||||
memset(data.data(), 0, sizeof(data));
|
||||
MutableBitSpan span{data.data(), 640};
|
||||
span.slice(IndexRange(5, 500)).set_all(true);
|
||||
|
||||
for (const int64_t i : IndexRange(640)) {
|
||||
EXPECT_EQ(span[i], i >= 5 && i < 505);
|
||||
}
|
||||
|
||||
span.slice(IndexRange(10, 190)).set_all(false);
|
||||
|
||||
for (const int64_t i : IndexRange(640)) {
|
||||
EXPECT_EQ(span[i], (i >= 5 && i < 10) || (i >= 200 && i < 505));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bits::tests
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "testing/testing.h"
|
||||
|
||||
namespace blender::tests {
|
||||
namespace blender::bits::tests {
|
||||
|
||||
TEST(bit_vector, DefaultConstructor)
|
||||
{
|
||||
|
@ -183,4 +183,4 @@ TEST(bit_vector, AppendMany)
|
|||
EXPECT_TRUE(vec[5]);
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
} // namespace blender::bits::tests
|
||||
|
|
|
@ -290,6 +290,24 @@ TEST(index_range, SplitByAlignment)
|
|||
EXPECT_EQ(ranges.aligned, IndexRange());
|
||||
EXPECT_EQ(ranges.suffix, IndexRange());
|
||||
}
|
||||
{
|
||||
AlignedIndexRanges ranges = split_index_range_by_alignment(IndexRange(64), 64);
|
||||
EXPECT_EQ(ranges.prefix, IndexRange());
|
||||
EXPECT_EQ(ranges.aligned, IndexRange(64));
|
||||
EXPECT_EQ(ranges.suffix, IndexRange());
|
||||
}
|
||||
{
|
||||
AlignedIndexRanges ranges = split_index_range_by_alignment(IndexRange(64, 64), 64);
|
||||
EXPECT_EQ(ranges.prefix, IndexRange());
|
||||
EXPECT_EQ(ranges.aligned, IndexRange(64, 64));
|
||||
EXPECT_EQ(ranges.suffix, IndexRange());
|
||||
}
|
||||
{
|
||||
AlignedIndexRanges ranges = split_index_range_by_alignment(IndexRange(4, 8), 64);
|
||||
EXPECT_EQ(ranges.prefix, IndexRange(4, 8));
|
||||
EXPECT_EQ(ranges.aligned, IndexRange());
|
||||
EXPECT_EQ(ranges.suffix, IndexRange());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -1601,6 +1601,12 @@ static bool version_merge_still_offsets(Sequence *seq, void * /*user_data*/)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool version_fix_delete_flag(Sequence *seq, void * /*user_data*/)
|
||||
{
|
||||
seq->flag &= ~SEQ_FLAG_DELETE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find
|
||||
* anchor and source items in the given list of modifiers, constraints etc., using only the
|
||||
* `subitem_local` data of the override property operation.
|
||||
|
@ -3907,6 +3913,66 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 305, 10)) {
|
||||
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype != SPACE_FILE) {
|
||||
continue;
|
||||
}
|
||||
SpaceFile *sfile = reinterpret_cast<SpaceFile *>(sl);
|
||||
if (!sfile->asset_params) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* When an asset browser uses the default import method, make it follow the new
|
||||
* preference setting. This means no effective default behavior change. */
|
||||
if (sfile->asset_params->import_type == FILE_ASSET_IMPORT_APPEND_REUSE) {
|
||||
sfile->asset_params->import_type = FILE_ASSET_IMPORT_FOLLOW_PREFS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "int", "shadow_pool_size")) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
scene->eevee.flag |= SCE_EEVEE_SHADOW_ENABLED;
|
||||
scene->eevee.shadow_pool_size = 512;
|
||||
scene->r.simplify_shadows = 1.0f;
|
||||
scene->r.simplify_shadows_render = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype == SPACE_VIEW3D) {
|
||||
View3D *v3d = (View3D *)sl;
|
||||
v3d->overlay.flag |= V3D_OVERLAY_SCULPT_CURVES_CAGE;
|
||||
v3d->overlay.sculpt_curves_cage_opacity = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix possible uncleared `SEQ_FLAG_DELETE` flag */
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
Editing *ed = SEQ_editing_get(scene);
|
||||
if (ed != nullptr) {
|
||||
SEQ_for_each_callback(&ed->seqbase, version_fix_delete_flag, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
|
||||
if (brush->ob_mode == OB_MODE_SCULPT_CURVES) {
|
||||
if (brush->curves_sculpt_settings->curve_parameter_falloff == nullptr) {
|
||||
brush->curves_sculpt_settings->curve_parameter_falloff = BKE_curvemapping_add(
|
||||
1, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
@ -3917,15 +3983,6 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
* \note Keep this message at the bottom of the function.
|
||||
*/
|
||||
{
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "int", "shadow_pool_size")) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
scene->eevee.flag |= SCE_EEVEE_SHADOW_ENABLED;
|
||||
scene->eevee.shadow_pool_size = 512;
|
||||
scene->r.simplify_shadows = 1.0f;
|
||||
scene->r.simplify_shadows_render = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep this block, even when empty. */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -773,6 +773,12 @@ void blo_do_versions_userdef(UserDef *userdef)
|
|||
userdef->gpu_backend = GPU_BACKEND_OPENGL;
|
||||
}
|
||||
|
||||
if (!USER_VERSION_ATLEAST(305, 10)) {
|
||||
LISTBASE_FOREACH (bUserAssetLibrary *, asset_library, &userdef->asset_libraries) {
|
||||
asset_library->import_method = ASSET_IMPORT_APPEND_REUSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
|
|
@ -211,7 +211,7 @@ void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
|||
|
||||
int BM_iter_mesh_bitmap_from_filter(const char itype,
|
||||
BMesh *bm,
|
||||
blender::BitVector<> &bitmap,
|
||||
blender::MutableBitSpan bitmap,
|
||||
bool (*test_fn)(BMElem *, void *user_data),
|
||||
void *user_data)
|
||||
{
|
||||
|
@ -234,7 +234,7 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
|
|||
}
|
||||
|
||||
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
|
||||
blender::BitVector<> &bitmap,
|
||||
blender::MutableBitSpan bitmap,
|
||||
bool (*test_fn)(BMFace *, void *user_data),
|
||||
void *user_data)
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "BLI_mempool.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "BLI_bit_vector.hh"
|
||||
# include "BLI_bit_span.hh"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -228,14 +228,14 @@ void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
|||
|
||||
int BM_iter_mesh_bitmap_from_filter(char itype,
|
||||
BMesh *bm,
|
||||
blender::BitVector<> &bitmap,
|
||||
blender::MutableBitSpan bitmap,
|
||||
bool (*test_fn)(BMElem *, void *user_data),
|
||||
void *user_data);
|
||||
/**
|
||||
* Needed when we want to check faces, but return a loop aligned array.
|
||||
*/
|
||||
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
|
||||
blender::BitVector<> &bitmap,
|
||||
blender::MutableBitSpan bitmap,
|
||||
bool (*test_fn)(BMFace *, void *user_data),
|
||||
void *user_data);
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ static Vector<MeshToBMeshLayerInfo> mesh_to_bm_copy_info_calc(const CustomData &
|
|||
std::array<int, CD_NUMTYPES> per_type_index;
|
||||
per_type_index.fill(0);
|
||||
for (const int i : IndexRange(bm_data.totlayer)) {
|
||||
CustomDataLayer &bm_layer = bm_data.layers[i];
|
||||
const CustomDataLayer &bm_layer = bm_data.layers[i];
|
||||
const eCustomDataType type = eCustomDataType(bm_layer.type);
|
||||
const int mesh_layer_index =
|
||||
bm_layer.name[0] == '\0' ?
|
||||
|
@ -318,11 +318,6 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
|||
CustomData_bmesh_merge(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP);
|
||||
}
|
||||
|
||||
const Vector<MeshToBMeshLayerInfo> vert_info = mesh_to_bm_copy_info_calc(mesh_vdata, bm->vdata);
|
||||
const Vector<MeshToBMeshLayerInfo> edge_info = mesh_to_bm_copy_info_calc(mesh_edata, bm->edata);
|
||||
const Vector<MeshToBMeshLayerInfo> poly_info = mesh_to_bm_copy_info_calc(mesh_pdata, bm->pdata);
|
||||
const Vector<MeshToBMeshLayerInfo> loop_info = mesh_to_bm_copy_info_calc(mesh_ldata, bm->ldata);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Shape Key */
|
||||
int tot_shape_keys = 0;
|
||||
|
@ -407,6 +402,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
|||
}
|
||||
}
|
||||
|
||||
const Vector<MeshToBMeshLayerInfo> vert_info = mesh_to_bm_copy_info_calc(mesh_vdata, bm->vdata);
|
||||
const Vector<MeshToBMeshLayerInfo> edge_info = mesh_to_bm_copy_info_calc(mesh_edata, bm->edata);
|
||||
const Vector<MeshToBMeshLayerInfo> poly_info = mesh_to_bm_copy_info_calc(mesh_pdata, bm->pdata);
|
||||
const Vector<MeshToBMeshLayerInfo> loop_info = mesh_to_bm_copy_info_calc(mesh_ldata, bm->ldata);
|
||||
if (is_new) {
|
||||
CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
|
||||
CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
|
||||
|
@ -1079,7 +1078,7 @@ static Vector<BMeshToMeshLayerInfo> bm_to_mesh_copy_info_calc(const CustomData &
|
|||
std::array<int, CD_NUMTYPES> per_type_index;
|
||||
per_type_index.fill(0);
|
||||
for (const int i : IndexRange(mesh_data.totlayer)) {
|
||||
CustomDataLayer &mesh_layer = mesh_data.layers[i];
|
||||
const CustomDataLayer &mesh_layer = mesh_data.layers[i];
|
||||
const eCustomDataType type = eCustomDataType(mesh_layer.type);
|
||||
const int bm_layer_index =
|
||||
mesh_layer.name[0] == '\0' ?
|
||||
|
@ -1166,7 +1165,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
&bm->ldata, CD_PROP_BOOL, BKE_uv_map_pin_name_get(layer_name, sub_layer_name));
|
||||
|
||||
/* If ever the uv map associated bool layers become optional in BMesh as well (like in Mesh)
|
||||
* this assert needs to be removed. For now it is a bug if they doin't exist. */
|
||||
* this assert needs to be removed. For now it is a bug if they don't exist. */
|
||||
BLI_assert(vertsel_layer_index >= 0 && edgesel_layer_index >= 0 && pin_layer_index >= 0);
|
||||
|
||||
int vertsel_offset = vertsel_layer_index >= 0 ? bm->ldata.layers[vertsel_layer_index].offset :
|
||||
|
|
|
@ -1197,8 +1197,8 @@ static void bmw_FaceLoopWalker_begin(BMWalker *walker, void *data)
|
|||
{
|
||||
BMwFaceLoopWalker *lwalk, owalk, *owalk_pt;
|
||||
BMEdge *e = data;
|
||||
/* BMesh *bm = walker->bm; */ /* UNUSED */
|
||||
/* int fcount = BM_edge_face_count(e); */ /* UNUSED */
|
||||
// BMesh *bm = walker->bm; /* UNUSED */
|
||||
// int fcount = BM_edge_face_count(e); /* UNUSED */
|
||||
|
||||
if (!bmw_FaceLoopWalker_edge_begins_loop(walker, e)) {
|
||||
return;
|
||||
|
|
|
@ -1183,7 +1183,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
|
|||
f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true);
|
||||
BMO_face_flag_enable(bm, f, ELE_NEW);
|
||||
|
||||
/* Copy for loop data, otherwise UVs and vcols are no good.
|
||||
/* Copy for loop data, otherwise UVs and vertex-colors are no good.
|
||||
* tiny speedup here we could be more clever and copy from known adjacent data
|
||||
* also - we could attempt to interpolate the loop data,
|
||||
* this would be much slower but more useful too. */
|
||||
|
|
|
@ -161,7 +161,7 @@ void Evaluator::compile_and_evaluate_shader_compile_unit(CompileState &compile_s
|
|||
void Evaluator::map_shader_operation_inputs_to_their_results(ShaderOperation *operation,
|
||||
CompileState &compile_state)
|
||||
{
|
||||
for (const auto &item : operation->get_inputs_to_linked_outputs_map().items()) {
|
||||
for (const auto item : operation->get_inputs_to_linked_outputs_map().items()) {
|
||||
Result &result = compile_state.get_result_from_output_socket(item.value);
|
||||
operation->map_input_to_result(item.key, &result);
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ Map<std::string, DOutputSocket> &ShaderOperation::get_inputs_to_linked_outputs_m
|
|||
|
||||
void ShaderOperation::compute_results_reference_counts(const Schedule &schedule)
|
||||
{
|
||||
for (const auto &item : output_sockets_to_output_identifiers_map_.items()) {
|
||||
for (const auto item : output_sockets_to_output_identifiers_map_.items()) {
|
||||
const int reference_count = number_of_inputs_linked_to_output_conditioned(
|
||||
item.key, [&](DInputSocket input) { return schedule.contains(input.node()); });
|
||||
|
||||
|
|
|
@ -702,6 +702,7 @@ set(GLSL_SRC
|
|||
engines/overlay/shaders/overlay_point_varying_color_frag.glsl
|
||||
engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
|
||||
engines/overlay/shaders/overlay_pointcloud_only_vert.glsl
|
||||
engines/overlay/shaders/overlay_sculpt_curves_cage_vert.glsl
|
||||
engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl
|
||||
engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl
|
||||
engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
|
||||
|
|
|
@ -197,6 +197,7 @@ void DRW_gpu_render_context_enable(void *re_gpu_context);
|
|||
void DRW_gpu_render_context_disable(void *re_gpu_context);
|
||||
|
||||
void DRW_deferred_shader_remove(struct GPUMaterial *mat);
|
||||
void DRW_deferred_shader_optimize_remove(struct GPUMaterial *mat);
|
||||
|
||||
/**
|
||||
* Get DrawData from the given ID-block. In order for this to work, we assume that
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue