BLI: refactor IndexMask for better performance and memory usage #104629

Merged
Jacques Lucke merged 254 commits from JacquesLucke/blender:index-mask-refactor into main 2023-05-24 18:11:47 +02:00
364 changed files with 7018 additions and 3639 deletions
Showing only changes of commit ffc934d4f5 - Show all commits

View File

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

View File

@ -524,7 +524,7 @@ endif()
if(NOT APPLE)
option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON)
option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF)
set(CYCLES_HIP_BINARIES_ARCH gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for")
set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx906 gfx90c gfx902 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 gfx1100 gfx1101 gfx1102 CACHE STRING "AMD HIP architectures to build binaries for")
mark_as_advanced(WITH_CYCLES_DEVICE_HIP)
mark_as_advanced(CYCLES_HIP_BINARIES_ARCH)
endif()
@ -625,8 +625,10 @@ mark_as_advanced(
# Vulkan
option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (only for development)" OFF)
option(WITH_VULKAN_GUARDEDALLOC "Use guardedalloc for host allocations done inside Vulkan (development option)" OFF)
mark_as_advanced(
WITH_VULKAN_BACKEND
WITH_VULKAN_GUARDEDALLOC
)
# Metal

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -105,11 +105,12 @@ GPUShader *BlenderFallbackDisplayShader::bind(int width, int height)
/* Bind shader now to enable uniform assignment. */
GPU_shader_bind(shader_program_);
GPU_shader_uniform_int(shader_program_, image_texture_location_, 0);
int slot = 0;
GPU_shader_uniform_int_ex(shader_program_, image_texture_location_, 1, 1, &slot);
float size[2];
size[0] = width;
size[1] = height;
GPU_shader_uniform_vector(shader_program_, fullscreen_location_, 2, 1, size);
GPU_shader_uniform_float_ex(shader_program_, fullscreen_location_, 2, 1, size);
return shader_program_;
}

View File

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

View File

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

View File

@ -51,7 +51,7 @@ static inline bool hipSupportsDevice(const int hipDevId)
hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
return (major >= 10);
return (major >= 9);
}
CCL_NAMESPACE_END

View File

@ -886,7 +886,7 @@ int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) c
{
/* Special trick for fast navigation: schedule multiple samples during fast navigation
* (which will prefer to use lower resolution to keep up with refresh rate). This gives more
* usable visual feedback for artists. There are a couple of tricks though. */
* usable visual feedback for artists. */
if (is_denoise_active_during_update()) {
/* When denoising is used during navigation prefer using a higher resolution with less samples
@ -896,25 +896,12 @@ int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) c
return 1;
}
if (resolution_divider <= pixel_size_) {
/* When resolution divider is at or below pixel size, schedule one sample. This doesn't effect
* the sample count at this resolution division, but instead assists in the calculation of
* the resolution divider. */
return 1;
}
if (resolution_divider == pixel_size_ * 2) {
/* When resolution divider is the previous step to the final resolution, schedule two samples.
* This is so that rendering on lower resolution does not exceed time that it takes to render
* first sample at the full resolution. */
return 2;
}
/* Always render 4 samples, even if scene is configured for less.
* The idea here is to have enough information on the screen. Resolution divider of 2 allows us
* to have 4 time extra samples, so overall worst case timing is the same as the final resolution
* at one sample. */
return 4;
/* 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: Changing this formula will change the formula in
* `RenderScheduler::calculate_resolution_divider_for_time()`. */
return min(max(1, resolution_divider / pixel_size_), 4);
}
bool RenderScheduler::work_need_adaptive_filter() const
@ -1100,9 +1087,10 @@ void RenderScheduler::update_start_resolution_divider()
/* TODO(sergey): Need to add hysteresis to avoid resolution divider bouncing around when actual
* render time is somewhere on a boundary between two resolutions. */
/* Never increase resolution to higher than the pixel size (which is possible if the scene is
* simple and compute device is fast). */
start_resolution_divider_ = max(resolution_divider_for_update, pixel_size_);
/* Don't let resolution drop below the desired one. It's better to be slow than provide an
* unreadable viewport render. */
start_resolution_divider_ = min(resolution_divider_for_update,
default_start_resolution_divider_);
VLOG_WORK << "Calculated resolution divider is " << start_resolution_divider_;
}
@ -1187,24 +1175,24 @@ void RenderScheduler::check_time_limit_reached()
int RenderScheduler::calculate_resolution_divider_for_time(double desired_time, double actual_time)
{
/* TODO(sergey): There should a non-iterative analytical formula here. */
const double ratio_between_times = actual_time / desired_time;
int resolution_divider = 1;
/* 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
* resolution divider is less than or equal to 4. Once the resolution divider increases above 4,
* 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. */
const int navigation_samples = get_num_samples_during_navigation(
ceil_to_int(ratio_between_times));
/* This algorithm iterates through resolution dividers until a divider is found that achieves
* the desired render time. A limit of default_start_resolution_divider_ is put in place as the
* maximum resolution divider to avoid an unreadable viewport due to a low resolution.
* pre_resolution_division_samples and post_resolution_division_samples are used in this
* calculation to better predict the performance impact of changing resolution divisions as
* the sample count can also change between resolution divisions. */
while (actual_time > desired_time && resolution_divider < default_start_resolution_divider_) {
int pre_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
resolution_divider = resolution_divider * 2;
int post_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
actual_time /= 4.0 * pre_resolution_division_samples / post_resolution_division_samples;
}
return resolution_divider;
return ceil_to_int(sqrt(navigation_samples * ratio_between_times));
}
int calculate_resolution_divider_for_resolution(int width, int height, int resolution)

View File

@ -412,11 +412,12 @@ if(WITH_CYCLES_CUDA_BINARIES)
# warn for other versions
if((CUDA_VERSION STREQUAL "101") OR
(CUDA_VERSION STREQUAL "102") OR
(CUDA_VERSION_MAJOR STREQUAL "11"))
(CUDA_VERSION_MAJOR STREQUAL "11") OR
(CUDA_VERSION_MAJOR STREQUAL "12"))
else()
message(WARNING
"CUDA version ${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR} detected, "
"build may succeed but only CUDA 11, 10.2 and 10.1 have been tested")
"build may succeed but only CUDA 12, 11, 10.2 and 10.1 have been tested")
endif()
# build for each arch
@ -514,6 +515,16 @@ if(WITH_CYCLES_CUDA_BINARIES)
else()
message(STATUS "CUDA binaries for ${arch} require CUDA 10 or earlier, skipped.")
endif()
elseif(${arch} MATCHES ".*_3.")
if(DEFINED CUDA11_NVCC_EXECUTABLE)
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
set(cuda_toolkit_root_dir ${CUDA11_TOOLKIT_ROOT_DIR})
elseif("${CUDA_VERSION}" LESS 120) # Support for sm_35, sm_37 was removed in CUDA 12
set(cuda_nvcc_executable ${CUDA_NVCC_EXECUTABLE})
set(cuda_toolkit_root_dir ${CUDA_TOOLKIT_ROOT_DIR})
else()
message(STATUS "CUDA binaries for ${arch} require CUDA 11 or earlier, skipped.")
endif()
elseif(${arch} MATCHES ".*_7." AND "${CUDA_VERSION}" LESS 100)
message(STATUS "CUDA binaries for ${arch} require CUDA 10.0+, skipped.")
elseif(${arch} MATCHES ".*_8.")

View File

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

View File

@ -478,10 +478,18 @@ ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
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;
return exp(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v));
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

View File

@ -573,7 +573,7 @@ void ShaderManager::device_update_common(Device * /*device*/,
kfilm->is_rec709 = is_rec709;
}
void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *scene)
void ShaderManager::device_free_common(Device * /*device*/, DeviceScene *dscene, Scene * /*scene*/)
{
dscene->shaders.free();
}

View File

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

View File

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

View File

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

View File

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

View File

@ -370,6 +370,7 @@ const bTheme U_theme_default = {
.clipping_border_3d = RGBA(0x3f3f3fff),
.bundle_solid = RGBA(0xc8c8c8ff),
.camera_path = RGBA(0x000000ff),
.camera_passepartout = RGBA(0x000000),
.gp_vertex_size = 3,
.gp_vertex = RGBA(0x000000ff),
.gp_vertex_select = RGBA(0xff8500ff),

View File

@ -30,7 +30,7 @@ def url_prefill_from_blender(*, addon_info=None):
"**Blender Version**\n"
)
fh.write(
"Broken: version: %s, branch: %s, commit date: %s %s, hash: `rB%s`\n" % (
"Broken: version: %s, branch: %s, commit date: %s %s, hash: `%s`\n" % (
bpy.app.version_string,
bpy.app.build_branch.decode('utf-8', 'replace'),
bpy.app.build_commit_date.decode('utf-8', 'replace'),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:
@ -3869,6 +3888,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()
@ -5310,6 +5330,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):
@ -6720,15 +6741,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")
@ -6755,6 +6776,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'
@ -7936,6 +7964,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'
@ -8013,6 +8063,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,
@ -8213,6 +8264,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,
)

View File

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

View File

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

View File

@ -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;
@ -23,11 +26,15 @@ struct ID;
namespace blender::asset_system {
class AssetLibrary;
class AssetRepresentation {
AssetIdentifier identifier_;
/** Indicate if this is a local or external asset, and as such, which of the union members below
* should be used. */
const bool is_local_id_ = false;
/** Asset library that owns this asset representation. */
const AssetLibrary *owner_asset_library_;
struct ExternalAsset {
std::string name;
@ -44,10 +51,13 @@ class AssetRepresentation {
/** Constructs an asset representation for an external ID. The asset will not be editable. */
AssetRepresentation(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata);
std::unique_ptr<AssetMetaData> metadata,
const AssetLibrary &owner_asset_library);
/** Constructs an asset representation for an ID stored in the current file. This makes the asset
* local and fully editable. */
AssetRepresentation(AssetIdentifier &&identifier, ID &id);
AssetRepresentation(AssetIdentifier &&identifier,
ID &id,
const AssetLibrary &owner_asset_library);
AssetRepresentation(AssetRepresentation &&other);
/* Non-copyable type. */
AssetRepresentation(const AssetRepresentation &other) = delete;
@ -63,8 +73,18 @@ 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;
};
} // namespace blender::asset_system
@ -73,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);

View File

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

View File

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

View File

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

View File

@ -169,13 +169,14 @@ AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_p
std::unique_ptr<AssetMetaData> metadata)
{
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
return asset_storage_->add_external_asset(std::move(identifier), name, std::move(metadata));
return asset_storage_->add_external_asset(
std::move(identifier), name, std::move(metadata), *this);
}
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
{
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
return asset_storage_->add_local_id_asset(std::move(identifier), id);
return asset_storage_->add_local_id_asset(std::move(identifier), id, *this);
}
bool AssetLibrary::remove_asset(AssetRepresentation &asset)
@ -259,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)) {

View File

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

View File

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

View File

@ -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"
@ -17,15 +19,24 @@ namespace blender::asset_system {
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata)
: identifier_(identifier), is_local_id_(false), external_asset_()
std::unique_ptr<AssetMetaData> metadata,
const AssetLibrary &owner_asset_library)
: identifier_(identifier),
is_local_id_(false),
owner_asset_library_(&owner_asset_library),
external_asset_()
{
external_asset_.name = name;
external_asset_.metadata_ = std::move(metadata);
}
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier, ID &id)
: identifier_(identifier), is_local_id_(true), local_asset_id_(&id)
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
ID &id,
const AssetLibrary &owner_asset_library)
: identifier_(identifier),
is_local_id_(true),
owner_asset_library_(&owner_asset_library),
local_asset_id_(&id)
{
if (!id.asset_data) {
throw std::invalid_argument("Passed ID is not an asset");
@ -70,11 +81,32 @@ 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_;
}
const AssetLibrary &AssetRepresentation::owner_asset_library() const
{
return *owner_asset_library_;
}
} // namespace blender::asset_system
using namespace blender;
@ -87,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
* \{ */

View File

@ -15,18 +15,21 @@
namespace blender::asset_system {
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier, ID &id)
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier,
ID &id,
const AssetLibrary &owner_asset_library)
{
return *local_id_assets_.lookup_key_or_add(
std::make_unique<AssetRepresentation>(std::move(identifier), id));
std::make_unique<AssetRepresentation>(std::move(identifier), id, owner_asset_library));
}
AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata)
std::unique_ptr<AssetMetaData> metadata,
const AssetLibrary &owner_asset_library)
{
return *external_assets_.lookup_key_or_add(
std::make_unique<AssetRepresentation>(std::move(identifier), name, std::move(metadata)));
return *external_assets_.lookup_key_or_add(std::make_unique<AssetRepresentation>(
std::move(identifier), name, std::move(metadata), owner_asset_library));
}
bool AssetStorage::remove_asset(AssetRepresentation &asset)

View File

@ -35,9 +35,12 @@ class AssetStorage {
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_external_asset(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata);
std::unique_ptr<AssetMetaData> metadata,
const AssetLibrary &owner_asset_library);
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier, ID &id);
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier,
ID &id,
const AssetLibrary &owner_asset_library);
/** See #AssetLibrary::remove_asset(). */
bool remove_asset(AssetRepresentation &asset);

View File

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

View File

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

View File

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

View File

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

View File

@ -137,6 +137,7 @@ bool CustomData_has_referenced(const struct CustomData *data);
* implemented for mloopuv/mloopcol, for now.
*/
void CustomData_data_copy_value(int type, const void *source, void *dest);
void CustomData_data_set_default_value(int type, void *elem);
/**
* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
@ -281,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);
/**
@ -304,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,
@ -444,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);
@ -506,6 +508,8 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_bmesh_set_default(struct CustomData *data, void **block);
void CustomData_bmesh_free_block(struct CustomData *data, void **block);
void CustomData_bmesh_alloc_block(struct CustomData *data, void **block);
/**
* Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
*/
@ -517,24 +521,6 @@ void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
void *block,
eCustomDataMask mask_exclude);
/**
* Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
* blocks of data. the CustomData's must not be compatible.
*
* \param use_default_init: initializes data which can't be copied,
* typically you'll want to use this if the BM_xxx create function
* is called with BM_CREATE_SKIP_CD flag
*/
void CustomData_to_bmesh_block(const struct CustomData *source,
struct CustomData *dest,
int src_index,
void **dest_block,
bool use_default_init);
void CustomData_from_bmesh_block(const struct CustomData *source,
struct CustomData *dest,
void *src_block,
int dest_index);
/**
* Query info over types.
*/
@ -743,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;

View File

@ -36,15 +36,15 @@ struct PropertyRNA;
/* Data Management */
/**
* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
* and the strip itself.
* Frees the given NLA strip, and calls #BKE_nlastrip_remove_and_free to
* remove and free all children strips.
*/
void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user);
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
@ -94,10 +94,33 @@ void BKE_nla_tracks_copy_from_adt(struct Main *bmain,
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.
*/
struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
/*
* Removes the given NLA strip from the list of strips provided.
*/
void BKE_nlastrip_remove(ListBase *strips, struct NlaStrip *strip);
/*
* Removes the given NLA strip from the list of strips provided, and frees it's memory.
*/
void BKE_nlastrip_remove_and_free(ListBase *strips, struct NlaStrip *strip, const bool do_id_user);
/**
* Add new NLA-strip to the top of the NLA stack - i.e.
* into the last track if space, or a new one otherwise.
@ -139,13 +162,9 @@ void BKE_nlastrips_sort_strips(ListBase *strips);
void BKE_nlastrips_add_strip_unsafe(ListBase *strips, struct NlaStrip *strip);
/**
* \brief NULL checks incoming strip and verifies no overlap / invalid
* configuration against other strips in NLA Track.
*
* \param strips:
* \param strip:
* \return true
* \return false
* NULL checks incoming strip and verifies no overlap / invalid
* configuration against other strips in NLA Track before calling
* #BKE_nlastrips_add_strip_unsafe.
*/
bool BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip);
@ -215,11 +234,16 @@ bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
/**
* Add the given NLA-Strip to the given NLA-Track, assuming that it
* isn't currently attached to another one.
* Add the given NLA-Strip to the given NLA-Track.
* Calls #BKE_nlastrips_add_strip to check if strip can be added.
*/
bool BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip, bool is_liboverride);
/**
* Remove the NLA-Strip from the given NLA-Track.
*/
void BKE_nlatrack_remove_strip(struct NlaTrack *track, struct NlaStrip *strip);
/**
* Get the extents of the given NLA-Track including gaps between strips,
* returning whether this succeeded or not

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -120,7 +120,7 @@ static void fill_mesh_topology(const int vert_offset,
}
}
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic && profile_point_num > 2;
if (has_caps) {
const int poly_num = main_segment_num * profile_segment_num;
const int cap_loop_offset = loop_offset + poly_num * 4;
@ -271,7 +271,7 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
const int profile_point_num = profile_offsets.size(i_profile);
const int profile_segment_num = curves::segments_num(profile_point_num, profile_cyclic);
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic && profile_point_num > 2;
const int tube_face_num = main_segment_num * profile_segment_num;
vert_offset += main_point_num * profile_point_num;

View File

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

View File

@ -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;
@ -3654,7 +3667,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
}
}
static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
void CustomData_bmesh_alloc_block(CustomData *data, void **block)
{
if (*block) {
CustomData_bmesh_free_block(data, block);
@ -3689,19 +3702,23 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
}
}
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n)
void CustomData_data_set_default_value(const int type, void *elem)
{
int offset = data->layers[n].offset;
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
if (typeInfo->set_default_value) {
typeInfo->set_default_value(POINTER_OFFSET(*block, offset), 1);
typeInfo->set_default_value(elem, 1);
}
else {
memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size);
memset(elem, 0, typeInfo->size);
}
}
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n)
{
const int offset = data->layers[n].offset;
CustomData_data_set_default_value(data->layers[n].type, POINTER_OFFSET(*block, offset));
}
void CustomData_bmesh_set_default(CustomData *data, void **block)
{
if (*block == nullptr) {
@ -3891,8 +3908,8 @@ void CustomData_data_copy_value(int type, const void *source, void *dest)
return;
}
if (typeInfo->copyvalue) {
typeInfo->copyvalue(source, dest, CDT_MIX_NOMIX, 0.0f);
if (typeInfo->copy) {
typeInfo->copy(source, dest, 1);
}
else {
memcpy(dest, source, typeInfo->size);
@ -4067,115 +4084,6 @@ void CustomData_bmesh_interp(CustomData *data,
}
}
void CustomData_to_bmesh_block(const CustomData *source,
CustomData *dest,
int src_index,
void **dest_block,
bool use_default_init)
{
if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
}
/* copies a layer at a time */
int dest_i = 0;
for (int src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
if (use_default_init) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
}
dest_i++;
}
/* if there are no more dest layers, we're done */
if (dest_i >= dest->totlayer) {
break;
}
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type) {
int offset = dest->layers[dest_i].offset;
const void *src_data = source->layers[src_i].data;
void *dest_data = POINTER_OFFSET(*dest_block, offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
const size_t src_offset = size_t(src_index) * typeInfo->size;
if (typeInfo->copy) {
typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
}
else {
memcpy(dest_data, POINTER_OFFSET(src_data, src_offset), typeInfo->size);
}
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
* increment dest_i
*/
dest_i++;
}
}
if (use_default_init) {
while (dest_i < dest->totlayer) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
dest_i++;
}
}
}
void CustomData_from_bmesh_block(const CustomData *source,
CustomData *dest,
void *src_block,
int dest_index)
{
/* copies a layer at a time */
int dest_i = 0;
for (int src_i = 0; src_i < source->totlayer; src_i++) {
if (source->layers[src_i].flag & CD_FLAG_NOCOPY) {
continue;
}
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
dest_i++;
}
/* if there are no more dest layers, we're done */
if (dest_i >= dest->totlayer) {
return;
}
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type) {
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
int offset = source->layers[src_i].offset;
const void *src_data = POINTER_OFFSET(src_block, offset);
void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data,
size_t(dest_index) * typeInfo->size);
if (typeInfo->copy) {
typeInfo->copy(src_data, dst_data, 1);
}
else {
memcpy(dst_data, src_data, typeInfo->size);
}
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
* increment dest_i
*/
dest_i++;
}
}
}
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@ -5308,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;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -61,7 +61,7 @@ static void nla_tweakmode_find_active(const ListBase /* NlaTrack */ *nla_tracks,
/* Freeing ------------------------------------------- */
void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
void BKE_nlastrip_free(NlaStrip *strip, const bool do_id_user)
{
NlaStrip *cs, *csn;
@ -73,7 +73,7 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
/* free child-strips */
for (cs = strip->strips.first; cs; cs = csn) {
csn = cs->next;
BKE_nlastrip_free(&strip->strips, cs, do_id_user);
BKE_nlastrip_remove_and_free(&strip->strips, cs, do_id_user);
}
/* remove reference to action */
@ -81,10 +81,6 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
id_us_min(&strip->act->id);
}
/* free remapping info */
// if (strip->remap)
// BKE_animremap_free();
/* free own F-Curves */
BKE_fcurves_free(&strip->fcurves);
@ -92,15 +88,10 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
free_fmodifiers(&strip->modifiers);
/* free the strip itself */
if (strips) {
BLI_freelinkN(strips, strip);
}
else {
MEM_freeN(strip);
}
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;
@ -112,16 +103,11 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
/* free strips */
for (strip = nlt->strips.first; strip; strip = stripn) {
stripn = strip->next;
BKE_nlastrip_free(&nlt->strips, strip, do_id_user);
BKE_nlastrip_remove_and_free(&nlt->strips, strip, 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)
@ -136,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 */
@ -523,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 */
@ -875,7 +875,7 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
}
/* free the meta-strip now */
BKE_nlastrip_free(strips, strip, true);
BKE_nlastrip_remove_and_free(strips, strip, true);
}
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
@ -1190,6 +1190,12 @@ bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_libove
return BKE_nlastrips_add_strip(&nlt->strips, strip);
}
void BKE_nlatrack_remove_strip(NlaTrack *track, NlaStrip *strip)
{
BLI_assert(track);
BKE_nlastrip_remove(&track->strips, strip);
}
bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
{
NlaStrip *strip;
@ -1318,6 +1324,18 @@ NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
return nlastrip_find_active(&nlt->strips);
}
void BKE_nlastrip_remove(ListBase *strips, NlaStrip *strip)
{
BLI_assert(strips);
BLI_remlink(strips, strip);
}
void BKE_nlastrip_remove_and_free(ListBase *strips, NlaStrip *strip, const bool do_id_user)
{
BKE_nlastrip_remove(strips, strip);
BKE_nlastrip_free(strip, do_id_user);
}
void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
{
NlaTrack *nlt;

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2023 Blender Foundation. All rights reserved. */
#include "BLI_listbase.h"
#include "BKE_nla.h"
#include "DNA_anim_types.h"
@ -20,19 +22,19 @@ TEST(nla_strip, BKE_nlastrip_recalculate_blend)
strip.start = 1;
strip.end = 10;
/* Scaling a strip up doesn't affect the blend in/out value */
/* Scaling a strip up doesn't affect the blend in/out value. */
strip.end = 20;
BKE_nlastrip_recalculate_blend(&strip);
EXPECT_FLOAT_EQ(strip.blendin, 4.0);
EXPECT_FLOAT_EQ(strip.blendout, 5.0);
/* Scaling a strip down affects the blend-in value before the blend-out value */
/* Scaling a strip down affects the blend-in value before the blend-out value. */
strip.end = 7;
BKE_nlastrip_recalculate_blend(&strip);
EXPECT_FLOAT_EQ(strip.blendin, 1.0);
EXPECT_FLOAT_EQ(strip.blendout, 5.0);
/* Scaling a strip down to nothing updates the blend in/out values accordingly */
/* Scaling a strip down to nothing updates the blend in/out values accordingly. */
strip.end = 1.1;
BKE_nlastrip_recalculate_blend(&strip);
EXPECT_FLOAT_EQ(strip.blendin, 0.0);
@ -63,4 +65,55 @@ TEST(nla_strip, BKE_nlastrips_add_strip)
EXPECT_TRUE(BKE_nlastrips_add_strip(&strips, &strip2));
}
TEST(nla_track, BKE_nlatrack_remove_strip)
{
NlaTrack track{};
ListBase strips{};
NlaStrip strip1{};
strip1.start = 0;
strip1.end = 10;
NlaStrip strip2{};
strip2.start = 11;
strip2.end = 20;
// Add NLA strips to the NLATrack.
BKE_nlastrips_add_strip(&strips, &strip1);
BKE_nlastrips_add_strip(&strips, &strip2);
track.strips = strips;
// ensure we have 2 strips in the track.
EXPECT_EQ(2, BLI_listbase_count(&track.strips));
BKE_nlatrack_remove_strip(&track, &strip2);
EXPECT_EQ(1, BLI_listbase_count(&track.strips));
// ensure the correct strip was removed.
EXPECT_EQ(-1, BLI_findindex(&track.strips, &strip2));
}
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -538,13 +538,14 @@ void tracking_cameraIntrinscisOptionsFromTracking(
void tracking_trackingCameraFromIntrinscisOptions(
MovieTracking *tracking, const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
{
float aspy = 1.0f / tracking->camera.pixel_aspect;
MovieTrackingCamera *camera = &tracking->camera;
camera->focal = camera_intrinsics_options->focal_length;
/* NOTE: The image size stored in the `camera_intrinsics_options` is aspect-ratio corrected,
* so there is no need to "un-apply" it from the principal point. */
const float principal_px[2] = {camera_intrinsics_options->principal_point_x,
camera_intrinsics_options->principal_point_y / (double)aspy};
camera_intrinsics_options->principal_point_y};
tracking_principal_point_pixel_to_normalized(principal_px,
camera_intrinsics_options->image_width,

View File

@ -16,13 +16,13 @@
*
* The compact nature of storing bools in individual bits has some downsides that have to be kept
* in mind:
* - Writing to separate bits in the same byte is not thread-safe. Therefore, an existing vector of
* - Writing to separate bits in the same int is not thread-safe. Therefore, an existing vector of
* bool can't easily be replaced with a bit vector, if it is written to from multiple threads.
* Read-only access from multiple threads is fine though.
* - Writing individual elements is more expensive when the array is in cache already. That is
* because changing a bit is always a read-modify-write operation on the byte the bit resides in.
* because changing a bit is always a read-modify-write operation on the int the bit resides in.
* - Reading individual elements is more expensive when the array is in cache already. That is
* because additional bit-wise operations have to be applied after the corresponding byte is
* because additional bit-wise operations have to be applied after the corresponding int is
* read.
*
* Comparison to `std::vector<bool>`:
@ -42,18 +42,27 @@
#include "BLI_memory_utils.hh"
#include "BLI_span.hh"
namespace blender {
namespace blender::bits {
/**
* This is a read-only pointer to a specific bit. The value of the bit can be retrieved, but not
* changed.
* 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 exact byte that the bit is in. */
const uint8_t *byte_ptr_;
/** 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. */
uint8_t mask_;
IntType mask_;
friend class MutableBitRef;
@ -61,13 +70,13 @@ class BitRef {
BitRef() = default;
/**
* Reference a specific bit in a byte array. Note that #byte_ptr does *not* have to point to the
* exact byte the bit is in.
* 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 uint8_t *byte_ptr, const int64_t bit_index)
BitRef(const IntType *ptr, const int64_t bit_index)
{
byte_ptr_ = byte_ptr + (bit_index >> 3);
mask_ = 1 << (bit_index & 7);
ptr_ = ptr + (bit_index >> BitToIntIndexShift);
mask_ = IntType(1) << (bit_index & BitIndexMask);
}
/**
@ -75,9 +84,9 @@ class BitRef {
*/
bool test() const
{
const uint8_t byte = *byte_ptr_;
const uint8_t masked_byte = byte & mask_;
return masked_byte != 0;
const IntType value = *ptr_;
const IntType masked_value = value & mask_;
return masked_value != 0;
}
operator bool() const
@ -91,22 +100,22 @@ class BitRef {
*/
class MutableBitRef {
private:
/** Points to the exact byte that the bit is in. */
uint8_t *byte_ptr_;
/** Points to the integer that the bit is in. */
IntType *ptr_;
/** All zeros except for a single one at the bit that is referenced. */
uint8_t mask_;
IntType mask_;
public:
MutableBitRef() = default;
/**
* Reference a specific bit in a byte array. Note that #byte_ptr does *not* have to point to the
* exact byte the bit is in.
* Reference a specific bit in an array. Note that #ptr does *not* have to point to the
* exact int the bit is in.
*/
MutableBitRef(uint8_t *byte_ptr, const int64_t bit_index)
MutableBitRef(IntType *ptr, const int64_t bit_index)
{
byte_ptr_ = byte_ptr + (bit_index >> 3);
mask_ = 1 << uint8_t(bit_index & 7);
ptr_ = ptr + (bit_index >> BitToIntIndexShift);
mask_ = IntType(1) << IntType(bit_index & BitIndexMask);
}
/**
@ -115,7 +124,7 @@ class MutableBitRef {
operator BitRef() const
{
BitRef bit_ref;
bit_ref.byte_ptr_ = byte_ptr_;
bit_ref.ptr_ = ptr_;
bit_ref.mask_ = mask_;
return bit_ref;
}
@ -125,9 +134,9 @@ class MutableBitRef {
*/
bool test() const
{
const uint8_t byte = *byte_ptr_;
const uint8_t masked_byte = byte & mask_;
return masked_byte != 0;
const IntType value = *ptr_;
const IntType masked_value = value & mask_;
return masked_value != 0;
}
operator bool() const
@ -140,7 +149,7 @@ class MutableBitRef {
*/
void set()
{
*byte_ptr_ |= mask_;
*ptr_ |= mask_;
}
/**
@ -148,7 +157,7 @@ class MutableBitRef {
*/
void reset()
{
*byte_ptr_ &= ~mask_;
*ptr_ &= ~mask_;
}
/**
@ -177,21 +186,20 @@ template<
typename Allocator = GuardedAllocator>
class BitVector {
private:
static constexpr int64_t required_bytes_for_bits(const int64_t number_of_bits)
static constexpr int64_t required_ints_for_bits(const int64_t number_of_bits)
{
return (number_of_bits + BitsPerByte - 1) / BitsPerByte;
return (number_of_bits + BitsPerInt - 1) / BitsPerInt;
}
static constexpr int64_t BitsPerByte = 8;
static constexpr int64_t BytesInInlineBuffer = required_bytes_for_bits(InlineBufferCapacity);
static constexpr int64_t BitsInInlineBuffer = BytesInInlineBuffer * BitsPerByte;
static constexpr int64_t AllocationAlignment = 8;
static constexpr int64_t IntsInInlineBuffer = required_ints_for_bits(InlineBufferCapacity);
static constexpr int64_t BitsInInlineBuffer = IntsInInlineBuffer * BitsPerInt;
static constexpr int64_t AllocationAlignment = alignof(IntType);
/**
* Points to the first byte used by the vector. It might point to the memory in the inline
* Points to the first integer used by the vector. It might point to the memory in the inline
* buffer.
*/
uint8_t *data_;
IntType *data_;
/** Current size of the vector in bits. */
int64_t size_in_bits_;
@ -203,7 +211,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<uint8_t, BytesInInlineBuffer> inline_buffer_;
BLI_NO_UNIQUE_ADDRESS TypedBuffer<IntType, IntsInInlineBuffer> inline_buffer_;
public:
BitVector(Allocator allocator = {}) noexcept : allocator_(allocator)
@ -211,7 +219,7 @@ class BitVector {
data_ = inline_buffer_;
size_in_bits_ = 0;
capacity_in_bits_ = BitsInInlineBuffer;
uninitialized_fill_n(data_, BytesInInlineBuffer, uint8_t(0));
uninitialized_fill_n(data_, IntsInInlineBuffer, IntType(0));
}
BitVector(NoExceptConstructor, Allocator allocator = {}) noexcept : BitVector(allocator)
@ -220,29 +228,29 @@ class BitVector {
BitVector(const BitVector &other) : BitVector(NoExceptConstructor(), other.allocator_)
{
const int64_t bytes_to_copy = other.used_bytes_amount();
const int64_t ints_to_copy = other.used_ints_amount();
if (other.size_in_bits_ <= BitsInInlineBuffer) {
/* The data is copied into the owned inline buffer. */
data_ = inline_buffer_;
capacity_in_bits_ = BitsInInlineBuffer;
}
else {
/* Allocate a new byte array because the inline buffer is too small. */
data_ = static_cast<uint8_t *>(
allocator_.allocate(bytes_to_copy, AllocationAlignment, __func__));
capacity_in_bits_ = bytes_to_copy * BitsPerByte;
/* Allocate a new array because the inline buffer is too small. */
data_ = static_cast<IntType *>(
allocator_.allocate(ints_to_copy * sizeof(IntType), AllocationAlignment, __func__));
capacity_in_bits_ = ints_to_copy * BitsPerInt;
}
size_in_bits_ = other.size_in_bits_;
uninitialized_copy_n(other.data_, bytes_to_copy, data_);
uninitialized_copy_n(other.data_, ints_to_copy, data_);
}
BitVector(BitVector &&other) noexcept : BitVector(NoExceptConstructor(), other.allocator_)
{
if (other.is_inline()) {
/* Copy the data into the inline buffer. */
const int64_t bytes_to_copy = other.used_bytes_amount();
const int64_t ints_to_copy = other.used_ints_amount();
data_ = inline_buffer_;
uninitialized_copy_n(other.data_, bytes_to_copy, data_);
uninitialized_copy_n(other.data_, ints_to_copy, data_);
}
else {
/* Steal the pointer. */
@ -305,7 +313,7 @@ class BitVector {
bool is_empty() const
{
return this->size() == 0;
return size_in_bits_ == 0;
}
/**
@ -442,20 +450,20 @@ class BitVector {
*/
void fill_range(const IndexRange range, const bool value)
{
const AlignedIndexRanges aligned_ranges = split_index_range_by_alignment(range, BitsPerByte);
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 bytes at once. */
const int64_t start_fill_byte_index = aligned_ranges.aligned.start() / BitsPerByte;
const int64_t bytes_to_fill = aligned_ranges.aligned.size() / BitsPerByte;
const uint8_t fill_value = value ? uint8_t(0xff) : uint8_t(0x00);
initialized_fill_n(data_ + start_fill_byte_index, bytes_to_fill, fill_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 byte. */
/* Fill bits in the end that don't cover a full int. */
for (const int64_t i : aligned_ranges.suffix) {
(*this)[i].set(value);
}
@ -509,37 +517,35 @@ class BitVector {
}
BLI_NOINLINE void realloc_to_at_least(const int64_t min_capacity_in_bits,
const uint8_t initial_value_for_new_bytes = 0x00)
const IntType initial_value_for_new_ints = 0x00)
{
if (capacity_in_bits_ >= min_capacity_in_bits) {
return;
}
const int64_t min_capacity_in_bytes = this->required_bytes_for_bits(min_capacity_in_bits);
const int64_t min_capacity_in_ints = this->required_ints_for_bits(min_capacity_in_bits);
/* At least double the size of the previous allocation. */
const int64_t min_new_capacity_in_bytes = capacity_in_bits_ * 2;
const int64_t min_new_capacity_in_ints = 2 * this->required_ints_for_bits(capacity_in_bits_);
const int64_t new_capacity_in_bytes = std::max(min_capacity_in_bytes,
min_new_capacity_in_bytes);
const int64_t bytes_to_copy = this->used_bytes_amount();
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();
uint8_t *new_data = static_cast<uint8_t *>(
allocator_.allocate(new_capacity_in_bytes, AllocationAlignment, __func__));
uninitialized_copy_n(data_, bytes_to_copy, new_data);
IntType *new_data = static_cast<IntType *>(allocator_.allocate(
new_capacity_in_ints * sizeof(IntType), 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
* uninitialized byte. */
uninitialized_fill_n(new_data + bytes_to_copy,
new_capacity_in_bytes - bytes_to_copy,
uint8_t(initial_value_for_new_bytes));
* uninitialized int. */
uninitialized_fill_n(
new_data + ints_to_copy, new_capacity_in_ints - ints_to_copy, initial_value_for_new_ints);
if (!this->is_inline()) {
allocator_.deallocate(data_);
}
data_ = new_data;
capacity_in_bits_ = new_capacity_in_bytes * BitsPerByte;
capacity_in_bits_ = new_capacity_in_ints * BitsPerInt;
}
bool is_inline() const
@ -547,10 +553,16 @@ class BitVector {
return data_ == inline_buffer_;
}
int64_t used_bytes_amount() const
int64_t used_ints_amount() const
{
return this->required_bytes_for_bits(size_in_bits_);
return this->required_ints_for_bits(size_in_bits_);
}
};
} // namespace blender::bits
namespace blender {
using bits::BitRef;
using bits::BitVector;
using bits::MutableBitRef;
} // namespace blender

View File

@ -97,8 +97,9 @@ MINLINE float saacos(float fac);
MINLINE float saasin(float fac);
MINLINE float sasqrt(float fac);
MINLINE float interpf(float a, float b, float t);
MINLINE double interpd(double a, double b, double t);
/* Compute linear interpolation (lerp) between origin and target. */
MINLINE float interpf(float target, float origin, float t);
MINLINE double interpd(double target, double origin, double t);
MINLINE float ratiof(float min, float max, float pos);
MINLINE double ratiod(double min, double max, double pos);

View File

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

View File

@ -283,10 +283,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
@ -493,13 +493,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

View File

@ -612,6 +612,25 @@ TEST(string, StrFormatIntegerUnits)
EXPECT_STREQ("-2B", size_str);
}
TEST(string, StringNLen)
{
EXPECT_EQ(0, BLI_strnlen("", 0));
EXPECT_EQ(0, BLI_strnlen("", 1));
EXPECT_EQ(0, BLI_strnlen("", 100));
EXPECT_EQ(0, BLI_strnlen("x", 0));
EXPECT_EQ(1, BLI_strnlen("x", 1));
EXPECT_EQ(1, BLI_strnlen("x", 100));
// ü is \xc3\xbc
EXPECT_EQ(2, BLI_strnlen("ü", 100));
EXPECT_EQ(0, BLI_strnlen("this is a longer string", 0));
EXPECT_EQ(1, BLI_strnlen("this is a longer string", 1));
EXPECT_EQ(5, BLI_strnlen("this is a longer string", 5));
EXPECT_EQ(47, BLI_strnlen("This string writes about an agent without name.", 100));
}
struct WordInfo {
WordInfo() = default;
WordInfo(int start, int end) : start(start), end(end)

View File

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

View File

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

View File

@ -85,6 +85,7 @@
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "BLI_vector.hh"
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
@ -110,6 +111,7 @@ using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
using blender::StringRef;
using blender::Vector;
static char bm_edge_flag_from_mflag(const short mflag)
{
@ -164,6 +166,63 @@ static BMFace *bm_face_create_from_mpoly(BMesh &bm,
return BM_face_create(&bm, verts.data(), edges.data(), loops.size(), nullptr, BM_CREATE_SKIP_CD);
}
struct MeshToBMeshLayerInfo {
eCustomDataType type;
/** The layer's position in the BMesh element's data block. */
int bmesh_offset;
/** The mesh's #CustomDataLayer::data. When null, the BMesh block is set to its default value. */
const void *mesh_data;
/** The size of every custom data element. */
size_t elem_size;
};
/**
* Calculate the necessary information to copy every data layer from the Mesh to the BMesh.
*/
static Vector<MeshToBMeshLayerInfo> mesh_to_bm_copy_info_calc(const CustomData &mesh_data,
CustomData &bm_data)
{
Vector<MeshToBMeshLayerInfo> infos;
std::array<int, CD_NUMTYPES> per_type_index;
per_type_index.fill(0);
for (const int i : IndexRange(bm_data.totlayer)) {
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' ?
CustomData_get_layer_index_n(&mesh_data, type, per_type_index[type]) :
CustomData_get_named_layer_index(&mesh_data, type, bm_layer.name);
MeshToBMeshLayerInfo info{};
info.type = type;
info.bmesh_offset = bm_layer.offset;
info.mesh_data = (mesh_layer_index == -1) ? nullptr : mesh_data.layers[mesh_layer_index].data;
info.elem_size = CustomData_get_elem_size(&bm_layer);
infos.append(info);
per_type_index[type]++;
}
return infos;
}
static void mesh_attributes_copy_to_bmesh_block(CustomData &data,
const Span<MeshToBMeshLayerInfo> copy_info,
const int mesh_index,
BMHeader &header)
{
CustomData_bmesh_alloc_block(&data, &header.data);
for (const MeshToBMeshLayerInfo &info : copy_info) {
if (info.mesh_data) {
CustomData_data_copy_value(info.type,
POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index),
POINTER_OFFSET(header.data, info.bmesh_offset));
}
else {
CustomData_data_set_default_value(info.type, POINTER_OFFSET(header.data, info.bmesh_offset));
}
}
}
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
{
if (!me) {
@ -343,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);
@ -393,8 +456,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
copy_v3_v3(v->no, vert_normals[i]);
}
/* Copy Custom Data */
CustomData_to_bmesh_block(&mesh_vdata, &bm->vdata, i, &v->head.data, true);
mesh_attributes_copy_to_bmesh_block(bm->vdata, vert_info, i, v->head);
/* Set shape key original index. */
if (cd_shape_keyindex_offset != -1) {
@ -432,8 +494,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_elem_flag_enable(e, BM_ELEM_SMOOTH);
}
/* Copy Custom Data */
CustomData_to_bmesh_block(&mesh_edata, &bm->edata, i, &e->head.data, true);
mesh_attributes_copy_to_bmesh_block(bm->edata, edge_info, i, e->head);
}
if (is_new) {
bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
@ -491,12 +552,11 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Don't use 'j' since we may have skipped some faces, hence some loops. */
BM_elem_index_set(l_iter, totloops++); /* set_ok */
/* Save index of corresponding #MLoop. */
CustomData_to_bmesh_block(&mesh_ldata, &bm->ldata, j++, &l_iter->head.data, true);
mesh_attributes_copy_to_bmesh_block(bm->ldata, loop_info, j, l_iter->head);
j++;
} while ((l_iter = l_iter->next) != l_first);
/* Copy Custom Data */
CustomData_to_bmesh_block(&mesh_pdata, &bm->pdata, i, &f->head.data, true);
mesh_attributes_copy_to_bmesh_block(bm->pdata, poly_info, i, f->head);
if (params->calc_face_normal) {
BM_face_normal_update(f);
@ -998,6 +1058,66 @@ static void convert_bmesh_selection_flags_to_mesh_attributes(BMesh &bm,
}
}
struct BMeshToMeshLayerInfo {
eCustomDataType type;
/** The layer's position in the BMesh element's data block. */
int bmesh_offset;
/** The mesh's #CustomDataLayer::data. When null, the BMesh block is set to its default value. */
void *mesh_data;
/** The size of every custom data element. */
size_t elem_size;
};
/**
* Calculate the necessary information to copy every data layer from the BMesh to the Mesh.
*/
static Vector<BMeshToMeshLayerInfo> bm_to_mesh_copy_info_calc(const CustomData &bm_data,
CustomData &mesh_data)
{
Vector<BMeshToMeshLayerInfo> infos;
std::array<int, CD_NUMTYPES> per_type_index;
per_type_index.fill(0);
for (const int i : IndexRange(mesh_data.totlayer)) {
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' ?
CustomData_get_layer_index_n(&bm_data, type, per_type_index[type]) :
CustomData_get_named_layer_index(&bm_data, type, mesh_layer.name);
/* Skip layers that don't exist in `bm_data` or are explicitly set to not be
* copied. The layers are either set separately or shouldn't exist on the mesh. */
if (bm_layer_index == -1) {
continue;
}
const CustomDataLayer &bm_layer = bm_data.layers[bm_layer_index];
if (bm_layer.flag & CD_FLAG_NOCOPY) {
continue;
}
BMeshToMeshLayerInfo info{};
info.type = type;
info.bmesh_offset = bm_layer.offset;
info.mesh_data = mesh_layer.data;
info.elem_size = CustomData_get_elem_size(&mesh_layer);
infos.append(info);
per_type_index[type]++;
}
return infos;
}
static void bmesh_block_copy_to_mesh_attributes(const Span<BMeshToMeshLayerInfo> copy_info,
const int mesh_index,
const void *block)
{
for (const BMeshToMeshLayerInfo &info : copy_info) {
CustomData_data_copy_value(info.type,
POINTER_OFFSET(block, info.bmesh_offset),
POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index));
}
}
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
{
using namespace blender;
@ -1011,6 +1131,8 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
const int ototvert = me->totvert;
blender::Vector<int> ldata_layers_marked_nocopy;
/* Free custom data. */
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
@ -1041,9 +1163,17 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
&bm->ldata, CD_PROP_BOOL, BKE_uv_map_edge_select_name_get(layer_name, sub_layer_name));
int pin_layer_index = CustomData_get_named_layer_index(
&bm->ldata, CD_PROP_BOOL, BKE_uv_map_pin_name_get(layer_name, sub_layer_name));
int vertsel_offset = bm->ldata.layers[vertsel_layer_index].offset;
int edgesel_offset = bm->ldata.layers[edgesel_layer_index].offset;
int pin_offset = bm->ldata.layers[pin_layer_index].offset;
/* 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 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 :
-1;
int edgesel_offset = edgesel_layer_index >= 0 ? bm->ldata.layers[edgesel_layer_index].offset :
-1;
int pin_offset = pin_layer_index >= 0 ? bm->ldata.layers[pin_layer_index].offset : -1;
bool need_vertsel = false;
bool need_edgesel = false;
bool need_pin = false;
@ -1051,10 +1181,20 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
need_vertsel |= BM_ELEM_CD_GET_BOOL(l, vertsel_offset);
need_edgesel |= BM_ELEM_CD_GET_BOOL(l, edgesel_offset);
need_pin |= BM_ELEM_CD_GET_BOOL(l, pin_offset);
if (vertsel_layer_index >= 0) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
need_vertsel |= BM_ELEM_CD_GET_BOOL(l, vertsel_offset);
}
}
if (edgesel_layer_index >= 0) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
need_edgesel |= BM_ELEM_CD_GET_BOOL(l, edgesel_offset);
}
}
if (pin_layer_index) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
need_pin |= BM_ELEM_CD_GET_BOOL(l, pin_offset);
}
}
}
@ -1063,18 +1203,21 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
else {
bm->ldata.layers[vertsel_layer_index].flag |= CD_FLAG_NOCOPY;
ldata_layers_marked_nocopy.append(vertsel_layer_index);
}
if (need_edgesel) {
bm->ldata.layers[edgesel_layer_index].flag &= ~CD_FLAG_NOCOPY;
}
else {
bm->ldata.layers[edgesel_layer_index].flag |= CD_FLAG_NOCOPY;
ldata_layers_marked_nocopy.append(edgesel_layer_index);
}
if (need_pin) {
bm->ldata.layers[pin_layer_index].flag &= ~CD_FLAG_NOCOPY;
}
else {
bm->ldata.layers[pin_layer_index].flag |= CD_FLAG_NOCOPY;
ldata_layers_marked_nocopy.append(pin_layer_index);
}
}
@ -1087,6 +1230,16 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly);
}
const Vector<BMeshToMeshLayerInfo> vert_info = bm_to_mesh_copy_info_calc(bm->vdata, me->vdata);
const Vector<BMeshToMeshLayerInfo> edge_info = bm_to_mesh_copy_info_calc(bm->edata, me->edata);
const Vector<BMeshToMeshLayerInfo> poly_info = bm_to_mesh_copy_info_calc(bm->pdata, me->pdata);
const Vector<BMeshToMeshLayerInfo> loop_info = bm_to_mesh_copy_info_calc(bm->ldata, me->ldata);
/* Clear the CD_FLAG_NOCOPY flags for the layers they were temporarily set on */
for (const int i : ldata_layers_marked_nocopy) {
bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY;
}
CustomData_add_layer_named(
&me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, me->totvert, "position");
CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, me->totedge);
@ -1119,8 +1272,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_elem_index_set(v, i); /* set_inline */
/* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->vdata, &me->vdata, v->head.data, i);
bmesh_block_copy_to_mesh_attributes(vert_info, i, v->head.data);
i++;
@ -1146,8 +1298,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BM_elem_index_set(e, i); /* set_inline */
/* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->edata, &me->edata, e->head.data, i);
bmesh_block_copy_to_mesh_attributes(edge_info, i, e->head.data);
i++;
BM_CHECK_ELEMENT(e);
@ -1176,8 +1327,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
mloop[j].e = BM_elem_index_get(l_iter->e);
mloop[j].v = BM_elem_index_get(l_iter->v);
/* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l_iter->head.data, j);
bmesh_block_copy_to_mesh_attributes(loop_info, j, l_iter->head.data);
j++;
BM_CHECK_ELEMENT(l_iter);
@ -1189,8 +1339,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
me->act_face = i;
}
/* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->pdata, &me->pdata, f->head.data, i);
bmesh_block_copy_to_mesh_attributes(poly_info, i, f->head.data);
i++;
BM_CHECK_ELEMENT(f);
@ -1399,12 +1548,13 @@ static void bm_to_mesh_verts(const BMesh &bm,
MutableSpan<bool> select_vert,
MutableSpan<bool> hide_vert)
{
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.vdata, mesh.vdata);
MutableSpan<float3> dst_vert_positions = mesh.vert_positions_for_write();
threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) {
for (const int vert_i : range) {
const BMVert &src_vert = *bm_verts[vert_i];
copy_v3_v3(dst_vert_positions[vert_i], src_vert.co);
CustomData_from_bmesh_block(&bm.vdata, &mesh.vdata, src_vert.head.data, vert_i);
bmesh_block_copy_to_mesh_attributes(info, vert_i, src_vert.head.data);
}
if (!select_vert.is_empty()) {
for (const int vert_i : range) {
@ -1426,6 +1576,7 @@ static void bm_to_mesh_edges(const BMesh &bm,
MutableSpan<bool> hide_edge,
MutableSpan<bool> sharp_edge)
{
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.edata, mesh.edata);
MutableSpan<MEdge> dst_edges = mesh.edges_for_write();
threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) {
for (const int edge_i : range) {
@ -1434,7 +1585,7 @@ static void bm_to_mesh_edges(const BMesh &bm,
dst_edge.v1 = BM_elem_index_get(src_edge.v1);
dst_edge.v2 = BM_elem_index_get(src_edge.v2);
dst_edge.flag = bm_edge_flag_to_mflag(&src_edge);
CustomData_from_bmesh_block(&bm.edata, &mesh.edata, src_edge.head.data, edge_i);
bmesh_block_copy_to_mesh_attributes(info, edge_i, src_edge.head.data);
}
if (!select_edge.is_empty()) {
for (const int edge_i : range) {
@ -1461,6 +1612,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
MutableSpan<bool> hide_poly,
MutableSpan<int> material_indices)
{
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata);
MutableSpan<MPoly> dst_polys = mesh.polys_for_write();
threading::parallel_for(dst_polys.index_range(), 1024, [&](const IndexRange range) {
for (const int face_i : range) {
@ -1469,7 +1621,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
dst_poly.totloop = src_face.len;
dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face));
dst_poly.flag = bm_face_flag_to_mflag(&src_face);
CustomData_from_bmesh_block(&bm.pdata, &mesh.pdata, src_face.head.data, face_i);
bmesh_block_copy_to_mesh_attributes(info, face_i, src_face.head.data);
}
if (!select_poly.is_empty()) {
for (const int face_i : range) {
@ -1491,6 +1643,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loops, Mesh &mesh)
{
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.ldata, mesh.ldata);
MutableSpan<MLoop> dst_loops = mesh.loops_for_write();
threading::parallel_for(dst_loops.index_range(), 1024, [&](const IndexRange range) {
for (const int loop_i : range) {
@ -1498,7 +1651,7 @@ static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loop
MLoop &dst_loop = dst_loops[loop_i];
dst_loop.v = BM_elem_index_get(src_loop.v);
dst_loop.e = BM_elem_index_get(src_loop.e);
CustomData_from_bmesh_block(&bm.ldata, &mesh.ldata, src_loop.head.data, loop_i);
bmesh_block_copy_to_mesh_attributes(info, loop_i, src_loop.head.data);
}
});
}

View File

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

View File

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

View File

@ -41,10 +41,10 @@ static float *parallel_reduction_dispatch(Context &context,
GPUTexture *reduced_texture = context.texture_pool().acquire(reduced_size, format);
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
const int texture_image_unit = GPU_shader_get_texture_binding(shader, "input_tx");
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, "input_tx");
GPU_texture_bind(texture_to_reduce, texture_image_unit);
const int image_unit = GPU_shader_get_texture_binding(shader, "output_img");
const int image_unit = GPU_shader_get_sampler_binding(shader, "output_img");
GPU_texture_image_bind(reduced_texture, image_unit);
GPU_compute_dispatch(shader, reduced_size.x, reduced_size.y, 1);

View File

@ -135,7 +135,7 @@ void MorphologicalDistanceFeatherWeights::compute_distance_falloffs(int type, in
void MorphologicalDistanceFeatherWeights::bind_weights_as_texture(GPUShader *shader,
const char *texture_name) const
{
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
GPU_texture_bind(weights_texture_, texture_image_unit);
}
@ -147,7 +147,7 @@ void MorphologicalDistanceFeatherWeights::unbind_weights_as_texture() const
void MorphologicalDistanceFeatherWeights::bind_distance_falloffs_as_texture(
GPUShader *shader, const char *texture_name) const
{
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
GPU_texture_bind(distance_falloffs_texture_, texture_image_unit);
}

View File

@ -103,7 +103,7 @@ SymmetricBlurWeights::~SymmetricBlurWeights()
void SymmetricBlurWeights::bind_as_texture(GPUShader *shader, const char *texture_name) const
{
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
GPU_texture_bind(texture_, texture_image_unit);
}

View File

@ -81,7 +81,7 @@ SymmetricSeparableBlurWeights::~SymmetricSeparableBlurWeights()
void SymmetricSeparableBlurWeights::bind_as_texture(GPUShader *shader,
const char *texture_name) const
{
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
GPU_texture_bind(texture_, texture_image_unit);
}

View File

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

View File

@ -82,7 +82,7 @@ void Result::bind_as_texture(GPUShader *shader, const char *texture_name) const
/* Make sure any prior writes to the texture are reflected before reading from it. */
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
GPU_texture_bind(texture_, texture_image_unit);
}
@ -93,7 +93,7 @@ void Result::bind_as_image(GPUShader *shader, const char *image_name, bool read)
GPU_memory_barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
const int image_unit = GPU_shader_get_texture_binding(shader, image_name);
const int image_unit = GPU_shader_get_sampler_binding(shader, image_name);
GPU_texture_image_bind(texture_, image_unit);
}

View File

@ -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()); });
@ -95,14 +95,14 @@ void ShaderOperation::bind_material_resources(GPUShader *shader)
* no uniforms. */
GPUUniformBuf *ubo = GPU_material_uniform_buffer_get(material_);
if (ubo) {
GPU_uniformbuf_bind(ubo, GPU_shader_get_uniform_block_binding(shader, GPU_UBO_BLOCK_NAME));
GPU_uniformbuf_bind(ubo, GPU_shader_get_ubo_binding(shader, GPU_UBO_BLOCK_NAME));
}
/* Bind color band textures needed by curve and ramp nodes. */
ListBase textures = GPU_material_textures(material_);
LISTBASE_FOREACH (GPUMaterialTexture *, texture, &textures) {
if (texture->colorband) {
const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture->sampler_name);
const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture->sampler_name);
GPU_texture_bind(*texture->colorband, texture_image_unit);
}
}

View File

@ -225,7 +225,7 @@ set(SRC
DRW_select_buffer.h
intern/DRW_gpu_wrapper.hh
intern/DRW_render.h
intern/draw_attributes.h
intern/draw_attributes.hh
intern/draw_cache.h
intern/draw_cache_extract.hh
intern/draw_cache_impl.h
@ -234,7 +234,7 @@ set(SRC
intern/draw_command.hh
intern/draw_common.h
intern/draw_common_shader_shared.h
intern/draw_curves_private.h
intern/draw_curves_private.hh
intern/draw_debug.h
intern/draw_debug.hh
intern/draw_hair_private.h
@ -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

View File

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

View File

@ -53,6 +53,7 @@ static void eevee_engine_init(void *ved)
stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
stl->g_data->valid_taa_history = (txl->taa_history != NULL);
stl->g_data->queued_shaders_count = 0;
stl->g_data->queued_optimise_shaders_count = 0;
stl->g_data->render_timesteps = 1;
stl->g_data->disable_ligthprobes = v3d &&
(v3d->object_type_exclude_viewport & (1 << OB_LIGHTPROBE));
@ -178,6 +179,11 @@ static void eevee_cache_finish(void *vedata)
if (g_data->queued_shaders_count > 0) {
SNPRINTF(ved->info, TIP_("Compiling Shaders (%d remaining)"), g_data->queued_shaders_count);
}
else if (g_data->queued_optimise_shaders_count > 0) {
SNPRINTF(ved->info,
TIP_("Optimizing Shaders (%d remaining)"),
g_data->queued_optimise_shaders_count);
}
}
/* As renders in an HDR off-screen buffer, we need draw everything once

View File

@ -1000,6 +1000,8 @@ typedef struct EEVEE_PrivateData {
/* Compiling shaders count. This is to track if a shader has finished compiling. */
int queued_shaders_count;
int queued_shaders_count_prev;
/* Optimizing shaders count. */
int queued_optimise_shaders_count;
/* LookDev Settings */
int studiolight_index;

View File

@ -1390,12 +1390,21 @@ struct GPUMaterial *EEVEE_material_get(
return nullptr;
}
switch (status) {
case GPU_MAT_SUCCESS:
break;
case GPU_MAT_QUEUED:
case GPU_MAT_SUCCESS: {
/* Determine optimization status for remaining compilations counter. */
int optimization_status = GPU_material_optimization_status(mat);
if (optimization_status == GPU_MAT_OPTIMIZATION_QUEUED) {
vedata->stl->g_data->queued_optimise_shaders_count++;
}
} break;
case GPU_MAT_QUEUED: {
vedata->stl->g_data->queued_shaders_count++;
mat = EEVEE_material_default_get(scene, ma, options);
break;
GPUMaterial *default_mat = EEVEE_material_default_get(scene, ma, options);
/* Mark pending material with its default material for future cache warming.*/
GPU_material_set_default(mat, default_mat);
/* Return default material. */
mat = default_mat;
} break;
case GPU_MAT_FAILED:
default:
ma = EEVEE_material_default_error_get();

View File

@ -507,6 +507,8 @@ GPUMaterial *ShaderModule::material_shader_get(const char *name,
this);
GPU_material_status_set(gpumat, GPU_MAT_QUEUED);
GPU_material_compile(gpumat);
/* Queue deferred material optimization. */
DRW_shader_queue_optimize_material(gpumat);
return gpumat;
}

View File

@ -409,7 +409,7 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
/* Offset in tiles from the origin to the center of the first tile-maps. */
int2 origin_offset = int2(round(float2(near_point) / tile_size));
/* Offset in tiles between the first andlod the last tile-maps. */
/* Offset in tiles between the first and the last tile-maps. */
int2 offset_vector = int2(round(farthest_tilemap_center / tile_size));
light.clipmap_base_offset = (offset_vector * (1 << 16)) / max_ii(levels_range.size() - 1, 1);

View File

@ -21,8 +21,7 @@ void main()
float light_count = 0.0;
uint light_cull = 0u;
vec2 px = gl_FragCoord.xy;
LIGHT_FOREACH_BEGIN_LOCAL(light_cull_buf, light_zbin_buf, light_tile_buf, px, vP_z, l_idx)
{
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, px, vP_z, l_idx) {
LightData light = light_buf[l_idx];
light_cull |= 1u << l_idx;
light_count += 1.0;

Some files were not shown because too many files have changed in this diff Show More