Fix: Use ShaderCreateInfo for Cycles fallback display. #104981

Closed
Jason Fielder wants to merge 89 commits from Jason-Fielder:CyclesFallbackDisplayShader_CreateInfo into blender-v3.5-release

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
112 changed files with 963 additions and 2345 deletions
Showing only changes of commit 74be1acc7a - Show all commits

8
.arcconfig Normal file
View File

@ -0,0 +1,8 @@
{
"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

@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
## Update and uncomment this in the release branch
# set(BLENDER_VERSION 3.1)
set(BLENDER_VERSION 3.5)
function(download_source dep)
set(TARGET_FILE ${${dep}_FILE})

View File

@ -10,7 +10,7 @@ ExternalProject_Add(external_epoxy
URL_HASH ${EPOXY_HASH_TYPE}=${EPOXY_HASH}
PREFIX ${BUILD_DIR}/epoxy
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/epoxy/src/external_epoxy/ < ${PATCH_DIR}/epoxy.diff
CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${MESON} setup --prefix ${LIBDIR}/epoxy --default-library ${EPOXY_LIB_TYPE} --libdir lib ${BUILD_DIR}/epoxy/src/external_epoxy-build ${BUILD_DIR}/epoxy/src/external_epoxy -Dtests=false ${MESON_BUILD_TYPE}
CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${MESON} setup --prefix ${LIBDIR}/epoxy --default-library ${EPOXY_LIB_TYPE} --libdir lib ${BUILD_DIR}/epoxy/src/external_epoxy-build ${BUILD_DIR}/epoxy/src/external_epoxy -Dtests=false
BUILD_COMMAND ninja
INSTALL_COMMAND ninja install
)

View File

@ -9,7 +9,7 @@ ExternalProject_Add(external_fribidi
URL_HASH ${FRIBIDI_HASH_TYPE}=${FRIBIDI_HASH}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
PREFIX ${BUILD_DIR}/fribidi
CONFIGURE_COMMAND ${MESON} setup --prefix ${LIBDIR}/fribidi ${MESON_BUILD_TYPE} -Ddocs=false --default-library static --libdir lib ${BUILD_DIR}/fribidi/src/external_fribidi-build ${BUILD_DIR}/fribidi/src/external_fribidi
CONFIGURE_COMMAND ${MESON} setup --prefix ${LIBDIR}/fribidi -Ddocs=false --default-library static --libdir lib ${BUILD_DIR}/fribidi/src/external_fribidi-build ${BUILD_DIR}/fribidi/src/external_fribidi
BUILD_COMMAND ninja
INSTALL_COMMAND ninja install
INSTALL_DIR ${LIBDIR}/fribidi

View File

@ -21,7 +21,6 @@ set(HARFBUZZ_EXTRA_OPTIONS
# Only used for command line utilities,
# disable as this would add an addition & unnecessary build-dependency.
-Dcairo=disabled
${MESON_BUILD_TYPE}
)
ExternalProject_Add(external_harfbuzz
@ -60,10 +59,3 @@ if(BUILD_MODE STREQUAL Release AND WIN32)
DEPENDEES install
)
endif()
if(BUILD_MODE STREQUAL Debug AND WIN32)
ExternalProject_Add_Step(external_harfbuzz after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/harfbuzz/lib/libharfbuzz.a ${HARVEST_TARGET}/harfbuzz/lib/libharfbuzz_d.lib
DEPENDEES install
)
endif()

View File

@ -15,7 +15,7 @@ llvm-config = '${LIBDIR}/llvm/bin/llvm-config'"
)
set(MESA_EXTRA_FLAGS
${MESON_BUILD_TYPE}
-Dbuildtype=release
-Dc_args=${MESA_CFLAGS}
-Dcpp_args=${MESA_CXXFLAGS}
-Dc_link_args=${MESA_LDFLAGS}

View File

@ -16,10 +16,8 @@ message("BuildMode = ${BUILD_MODE}")
if(BUILD_MODE STREQUAL "Debug")
set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Debug)
set(MESON_BUILD_TYPE -Dbuildtype=debug)
else()
set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Release)
set(MESON_BUILD_TYPE -Dbuildtype=release)
endif()
set(DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/downloads" CACHE STRING "Path for downloaded files")

View File

@ -13,7 +13,7 @@ ExternalProject_Add(external_wayland
# NOTE: `-lm` is needed for `libxml2` which is a static library that uses `libm.so`,
# without this, math symbols such as `floor` aren't found.
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:${LIBDIR}/ffi/lib/pkgconfig:$PKG_CONFIG_PATH
${MESON} --prefix ${LIBDIR}/wayland ${MESON_BUILD_TYPE} -Ddocumentation=false -Dtests=false -D "c_link_args=-L${LIBDIR}/ffi/lib -lm" . ../external_wayland
${MESON} --prefix ${LIBDIR}/wayland -Ddocumentation=false -Dtests=false -D "c_link_args=-L${LIBDIR}/ffi/lib -lm" . ../external_wayland
BUILD_COMMAND ninja
INSTALL_COMMAND ninja install
)

View File

@ -7,7 +7,7 @@ ExternalProject_Add(external_wayland_protocols
PREFIX ${BUILD_DIR}/wayland-protocols
# Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own WAYLAND.
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/wayland/lib64/pkgconfig:$PKG_CONFIG_PATH
${MESON} --prefix ${LIBDIR}/wayland-protocols ${MESON_BUILD_TYPE} . ../external_wayland_protocols -Dtests=false
${MESON} --prefix ${LIBDIR}/wayland-protocols . ../external_wayland_protocols -Dtests=false
BUILD_COMMAND ninja
INSTALL_COMMAND ninja install
)

View File

@ -17,13 +17,11 @@ ExternalProject_Add(external_xvidcore
INSTALL_DIR ${LIBDIR}/xvidcore
)
if(WIN32)
ExternalProject_Add_Step(external_xvidcore after_install
COMMAND ${CMAKE_COMMAND} -E rename ${LIBDIR}/xvidcore/lib/xvidcore.a ${LIBDIR}/xvidcore/lib/libxvidcore.a || true
COMMAND ${CMAKE_COMMAND} -E remove ${LIBDIR}/xvidcore/lib/xvidcore.dll.a
DEPENDEES install
)
endif()
ExternalProject_Add_Step(external_xvidcore after_install
COMMAND ${CMAKE_COMMAND} -E rename ${LIBDIR}/xvidcore/lib/xvidcore.a ${LIBDIR}/xvidcore/lib/libxvidcore.a || true
COMMAND ${CMAKE_COMMAND} -E remove ${LIBDIR}/xvidcore/lib/xvidcore.dll.a
DEPENDEES install
)
if(MSVC)
set_target_properties(external_xvidcore PROPERTIES FOLDER Mingw)

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 OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_HIP_BINARIES ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_DEVICE_ONEAPI ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_ONEAPI_BINARIES ON CACHE BOOL "" FORCE)
endif()

View File

@ -142,7 +142,7 @@ def cmake_advanced_info() -> Union[Tuple[List[str], List[Tuple[str, str]]], Tupl
make_exe = cmake_cache_var("CMAKE_MAKE_PROGRAM")
if make_exe is None:
print("Make command not found: CMAKE_MAKE_PROGRAM")
print("Make command not found in: %r not found" % project_path)
return None, None
make_exe_basename = os.path.basename(make_exe)

View File

@ -5,38 +5,38 @@
update-code:
git:
submodules:
- branch: main
- branch: blender-v3.5-release
commit_id: HEAD
path: release/scripts/addons
- branch: main
- branch: blender-v3.5-release
commit_id: HEAD
path: release/scripts/addons_contrib
- branch: main
- branch: blender-v3.5-release
commit_id: HEAD
path: release/datafiles/locale
- branch: main
- branch: blender-v3.5-release
commit_id: HEAD
path: source/tools
svn:
libraries:
darwin-arm64:
branch: trunk
branch: tags/blender-3.5-release
commit_id: HEAD
path: lib/darwin_arm64
darwin-x86_64:
branch: trunk
branch: tags/blender-3.5-release
commit_id: HEAD
path: lib/darwin
linux-x86_64:
branch: trunk
branch: tags/blender-3.5-release
commit_id: HEAD
path: lib/linux_x86_64_glibc_228
windows-amd64:
branch: trunk
branch: tags/blender-3.5-release
commit_id: HEAD
path: lib/win64_vc15
tests:
branch: trunk
branch: tags/blender-3.5-release
commit_id: HEAD
path: lib/tests
benchmarks:

View File

@ -52,11 +52,9 @@ def get_blender_git_root() -> str:
# Setup for precompiled libraries and tests from svn.
def get_effective_architecture(args: argparse.Namespace) -> str:
architecture = args.architecture
if architecture:
assert isinstance(architecture, str)
return architecture
def get_effective_architecture(args: argparse.Namespace):
if args.architecture:
return args.architecture
# Check platform.version to detect arm64 with x86_64 python binary.
if "ARM64" in platform.version():
@ -275,7 +273,7 @@ if __name__ == "__main__":
major = blender_version.version // 100
minor = blender_version.version % 100
branch = f"blender-v{major}.{minor}-release"
release_version: Optional[str] = f"{major}.{minor}"
release_version = f"{major}.{minor}"
else:
branch = 'main'
release_version = None

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.6
PROJECT_NUMBER = V3.5
# 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

@ -1676,20 +1676,17 @@ 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':
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)
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

@ -42,15 +42,12 @@ endif()
###########################################################################
if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
set(WITH_CYCLES_HIP_BINARIES OFF)
message(STATUS "HIP temporarily disabled due to compiler bugs")
find_package(HIP)
set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES)
# 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()
if(HIP_FOUND)
message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})")
endif()
endif()
if(NOT WITH_HIP_DYNLOAD)

View File

@ -122,7 +122,7 @@ KERNEL_STRUCT_MEMBER(guiding, bool, use_surface_guiding, KERNEL_FEATURE_PATH_GUI
KERNEL_STRUCT_MEMBER(guiding, float, sample_surface_guiding_rand, KERNEL_FEATURE_PATH_GUIDING)
/* The probability to use surface guiding (i.e., diffuse sampling prob * guiding prob)*/
KERNEL_STRUCT_MEMBER(guiding, float, surface_guiding_sampling_prob, KERNEL_FEATURE_PATH_GUIDING)
/* Probability of sampling a BSSRDF closure instead of a BSDF closure. */
/* Probability of sampling a BSSRDF closure instead of a BSDF closure*/
KERNEL_STRUCT_MEMBER(guiding, float, bssrdf_sampling_prob, KERNEL_FEATURE_PATH_GUIDING)
/* If volume guiding is enabled */
KERNEL_STRUCT_MEMBER(guiding, bool, use_volume_guiding, KERNEL_FEATURE_PATH_GUIDING)

View File

@ -1177,7 +1177,7 @@ void LightManager::device_update(Device *device,
void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_background)
{
/* TODO: check if the light tree member variables need to be wrapped in a conditional too. */
/* to-do: check if the light tree member variables need to be wrapped in a conditional too*/
dscene->light_tree_nodes.free();
dscene->light_tree_emitters.free();
dscene->light_to_tree.free();

View File

@ -306,23 +306,14 @@ static void gwl_window_frame_update_from_pending(GWL_Window *win);
#ifdef USE_EVENT_BACKGROUND_THREAD
enum eGWL_PendingWindowActions {
/**
* 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,
PENDING_FRAME_CONFIGURE = 0,
PENDING_EGL_RESIZE,
# ifdef GHOST_OPENGL_ALPHA
/** Draw an opaque region behind the window. */
PENDING_OPAQUE_SET,
# endif
/**
* 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,
PENDING_SCALE_UPDATE,
};
# define PENDING_NUM (PENDING_OUTPUT_SCALE_UPDATE + 1)
# define PENDING_NUM (PENDING_SCALE_UPDATE + 1)
static void gwl_window_pending_actions_tag(GWL_Window *win, enum eGWL_PendingWindowActions type)
{
@ -332,10 +323,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_WINDOW_FRAME_CONFIGURE].exchange(false)) {
if (win->pending_actions[PENDING_FRAME_CONFIGURE].exchange(false)) {
gwl_window_frame_update_from_pending(win);
}
if (win->pending_actions[PENDING_EGL_WINDOW_RESIZE].exchange(false)) {
if (win->pending_actions[PENDING_EGL_RESIZE].exchange(false)) {
wl_egl_window_resize(win->egl_window, UNPACK2(win->frame.size), 0, 0);
}
# ifdef GHOST_OPENGL_ALPHA
@ -343,7 +334,7 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
win->ghost_window->setOpaque();
}
# endif
if (win->pending_actions[PENDING_OUTPUT_SCALE_UPDATE].exchange(false)) {
if (win->pending_actions[PENDING_SCALE_UPDATE].exchange(false)) {
win->ghost_window->outputs_changed_update_scale();
}
}
@ -351,10 +342,9 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
#endif /* USE_EVENT_BACKGROUND_THREAD */
/**
* Update the window's #GWL_WindowFrame.
* The caller must handle locking & run from the main thread.
* Update the window's #GWL_WindowFrame
*/
static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
static void gwl_window_frame_update_from_pending_lockfree(GWL_Window *win)
{
#ifdef USE_EVENT_BACKGROUND_THREAD
GHOST_ASSERT(win->ghost_system->main_thread_id == std::this_thread::get_id(),
@ -391,7 +381,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_no_lock(win);
gwl_window_frame_update_from_pending_lockfree(win);
}
/** \} */
@ -586,12 +576,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_WINDOW_FRAME_CONFIGURE);
gwl_window_pending_actions_tag(win, PENDING_FRAME_CONFIGURE);
}
else
# endif
{
gwl_window_frame_update_from_pending_no_lock(win);
gwl_window_frame_update_from_pending_lockfree(win);
}
}
}
@ -681,7 +671,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_WINDOW_FRAME_CONFIGURE);
gwl_window_pending_actions_tag(win, PENDING_FRAME_CONFIGURE);
}
else
#endif
@ -1383,7 +1373,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_OUTPUT_SCALE_UPDATE);
gwl_window_pending_actions_tag(window_, PENDING_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)};
adjustWindowRectForDesktop(&win_rect, style, extended_style);
adjustWindowRectForClosestMonitor(&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,55 +298,24 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
m_directManipulationHelper = NULL;
}
void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle)
void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
DWORD dwStyle,
DWORD dwExStyle)
{
/* 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;
/* Get Details of the closest monitor. */
HMONITOR hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
MONITORINFOEX monitor;
monitor.cbSize = sizeof(MONITORINFOEX);
monitor.dwFlags = 0;
/* We'll need this value before it is altered for checking later. */
LONG requested_top = win_rect->top;
/* 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);
/* 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;
/* With Windows 10 and newer we can adjust for chrome that differs with DPI and scale. */
GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr;
@ -358,9 +327,6 @@ void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyl
/* Adjust to allow for caption, borders, shadows, scaling, etc. Resulting values can be
* correctly outside of monitor bounds. NOTE: You cannot specify #WS_OVERLAPPED when calling. */
if (fpAdjustWindowRectExForDpi) {
/* Use the DPI of the monitor that is at the middle of the rect. */
hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
GetMonitorInfo(hmonitor, &monitor);
UINT dpiX, dpiY;
GetDpiForMonitor(hmonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
fpAdjustWindowRectExForDpi(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle, dpiX);
@ -369,12 +335,7 @@ void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyl
AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle);
}
/* Don't hide the title bar. Check the working area of the monitor at the top-left corner, using
* the original top since the justWindowRects might have altered it to different monitor. */
pt.x = win_rect->left;
pt.y = requested_top;
hmonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
GetMonitorInfo(hmonitor, &monitor);
/* But never allow a top position that can hide part of the title bar. */
win_rect->top = max(monitor.rcWork.top, win_rect->top);
}

View File

@ -87,12 +87,12 @@ class GHOST_WindowWin32 : public GHOST_Window {
~GHOST_WindowWin32();
/**
* Adjusts a requested window rect to fit and position within the desktop.
* Adjusts a requested window rect to fit and position correctly in monitor.
* \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 adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle);
void adjustWindowRectForClosestMonitor(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle);
/**
* Returns indication as to whether the window is valid.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 KiB

After

Width:  |  Height:  |  Size: 678 KiB

View File

@ -101,7 +101,11 @@ const UserDef U_default = {
.gp_euclideandist = 2,
.gp_eraser = 25,
.gp_settings = 0,
#ifdef __APPLE__
.gpu_backend = GPU_BACKEND_METAL,
#else
.gpu_backend = GPU_BACKEND_OPENGL,
#endif
/** Initialized by: #BKE_studiolight_default. */
.light_param = {{0}},

View File

@ -3513,9 +3513,6 @@ def km_animation_channels(params):
("anim.channels_ungroup", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Menus.
*_template_items_context_menu("DOPESHEET_MT_channel_context_menu", params.context_menu_event),
# View
("anim.channel_view_pick", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "alt": True}, None),
("anim.channels_view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
])
return keymap
@ -5634,8 +5631,6 @@ def km_curves(params):
("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

View File

@ -604,7 +604,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
colliding_names = []
for collection in (
# Built-in names.
{"shade_smooth": None, "crease": None},
{"shade_smooth": None, "normal": None, "crease": None},
mesh.attributes,
None if ob is None else ob.vertex_groups,
):

View File

@ -474,9 +474,6 @@ class DOPESHEET_MT_channel(Menu):
layout.separator()
layout.operator("anim.channels_fcurves_enable")
layout.separator()
layout.operator("anim.channels_view_selected")
class DOPESHEET_MT_key(Menu):
bl_label = "Key"
@ -604,9 +601,6 @@ class DOPESHEET_MT_gpencil_channel(Menu):
layout.separator()
layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
layout.separator()
layout.operator("anim.channels_view_selected")
class DOPESHEET_MT_gpencil_key(Menu):
bl_label = "Key"
@ -695,9 +689,6 @@ class DOPESHEET_MT_channel_context_menu(Menu):
# This menu is used from the graph editor too.
is_graph_editor = context.area.type == 'GRAPH_EDITOR'
layout.separator()
layout.operator("anim.channels_view_selected")
layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE'
layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE'
layout.separator()

View File

@ -239,9 +239,6 @@ class GRAPH_MT_channel(Menu):
layout.separator()
layout.operator("anim.channels_fcurves_enable")
layout.separator()
layout.operator("anim.channels_view_selected")
class GRAPH_MT_key(Menu):
bl_label = "Key"

View File

@ -574,11 +574,6 @@ class NODE_MT_context_menu(Menu):
layout.menu("NODE_MT_context_menu_select_menu")
layout.menu("NODE_MT_context_menu_show_hide_menu")
if active_node:
layout.separator()
props = layout.operator("wm.doc_view_manual", text="Online Manual", icon='URL')
props.doc_id = active_node.bl_idname
class NODE_PT_active_node_generic(Panel):
bl_space_type = 'NODE_EDITOR'

View File

@ -2044,16 +2044,6 @@ 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"
@ -2063,17 +2053,10 @@ 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"
@ -8063,7 +8046,6 @@ 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,

View File

@ -41,7 +41,6 @@ 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 306
#define BLENDER_VERSION 305
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
#define BLENDER_VERSION_CYCLE alpha
#define BLENDER_VERSION_CYCLE beta
/* TODO proper version bump. */
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 0
#define BLENDER_FILE_SUBVERSION 10
/* 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

@ -108,7 +108,7 @@ BVHTree *bvhtree_from_editmesh_verts(
*/
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
blender::BitSpan mask,
const blender::BitVector<> &mask,
int verts_num_active,
float epsilon,
int tree_type,
@ -124,7 +124,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
const float (*vert_positions)[3],
int verts_num,
blender::BitSpan verts_mask,
const blender::BitVector<> &verts_mask,
int verts_num_active,
float epsilon,
int tree_type,
@ -138,7 +138,7 @@ BVHTree *bvhtree_from_editmesh_edges(
*/
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
blender::BitSpan edges_mask,
const blender::BitVector<> &edges_mask,
int edges_num_active,
float epsilon,
int tree_type,
@ -156,7 +156,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
const float (*vert_positions)[3],
const struct MEdge *edge,
int edges_num,
blender::BitSpan edges_mask,
const blender::BitVector<> &edges_mask,
int edges_num_active,
float epsilon,
int tree_type,
@ -170,7 +170,7 @@ BVHTree *bvhtree_from_editmesh_looptri(
*/
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
blender::BitSpan mask,
const blender::BitVector<> &mask,
int looptri_num_active,
float epsilon,
int tree_type,
@ -184,7 +184,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
int looptri_num,
blender::BitSpan mask,
const blender::BitVector<> &mask,
int looptri_num_active,
float epsilon,
int tree_type,

View File

@ -282,7 +282,6 @@ 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);
/**

View File

@ -373,8 +373,6 @@ bool BKE_fcurve_calc_range(
/**
* Calculate the extents of F-Curve's data.
* \param range Only calculate the bounds of the FCurve in the given range.
* Does the full range if NULL.
*/
bool BKE_fcurve_calc_bounds(const struct FCurve *fcu,
float *xmin,
@ -382,8 +380,7 @@ bool BKE_fcurve_calc_bounds(const struct FCurve *fcu,
float *ymin,
float *ymax,
bool do_sel_only,
bool include_handles,
const float range[2]);
bool include_handles);
/**
* Return an array of keyed frames, rounded to `interval`.

View File

@ -41,10 +41,10 @@ struct PropertyRNA;
*/
void BKE_nlastrip_free(struct NlaStrip *strip, bool do_id_user);
/**
* Remove & Frees all NLA strips from the given NLA track,
* then frees (doesn't remove) the track itself.
* Remove the given NLA track from the set of NLA tracks, free the track's data,
* and the track itself.
*/
void BKE_nlatrack_free(struct NlaTrack *nlt, bool do_id_user);
void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user);
/**
* Free the elements of type NLA Tracks provided in the given list, but do not free
* the list itself since that is not free-standing
@ -95,17 +95,6 @@ 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.
*/

View File

@ -316,6 +316,9 @@ 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,6 +37,10 @@ class BuiltinAttributeProvider {
Creatable,
NonCreatable,
};
enum WritableEnum {
Writable,
Readonly,
};
enum DeletableEnum {
Deletable,
NonDeletable,
@ -47,6 +51,7 @@ class BuiltinAttributeProvider {
const eAttrDomain domain_;
const eCustomDataType data_type_;
const CreatableEnum createable_;
const WritableEnum writable_;
const DeletableEnum deletable_;
const AttributeValidator validator_;
@ -55,12 +60,14 @@ 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)
{
@ -198,14 +205,20 @@ 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, deletable, validator),
: BuiltinAttributeProvider(std::move(attribute_name),
domain,
attribute_type,
creatable,
writable,
deletable,
validator),
stored_type_(stored_type),
custom_data_access_(custom_data_access),
as_read_attribute_(as_read_attribute),

View File

@ -29,7 +29,6 @@
#include "MEM_guardedalloc.h"
using blender::BitSpan;
using blender::BitVector;
using blender::float3;
using blender::IndexRange;
@ -673,7 +672,7 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree(float epsilon,
int tree_type,
int axis,
BMEditMesh *em,
const BitSpan verts_mask,
const BitVector<> &verts_mask,
int verts_num_active)
{
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
@ -707,7 +706,7 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
int axis,
const float (*positions)[3],
const int verts_num,
const BitSpan verts_mask,
const BitVector<> &verts_mask,
int verts_num_active)
{
if (!verts_mask.is_empty()) {
@ -738,7 +737,7 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BitSpan verts_mask,
const BitVector<> &verts_mask,
int verts_num_active,
float epsilon,
int tree_type,
@ -765,7 +764,7 @@ BVHTree *bvhtree_from_editmesh_verts(
BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
const float (*vert_positions)[3],
const int verts_num,
const BitSpan verts_mask,
const BitVector<> &verts_mask,
int verts_num_active,
float epsilon,
int tree_type,
@ -795,7 +794,7 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
int tree_type,
int axis,
BMEditMesh *em,
const BitSpan edges_mask,
const BitVector<> &edges_mask,
int edges_num_active)
{
BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
@ -834,7 +833,7 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
const MEdge *edge,
const int edge_num,
const BitSpan edges_mask,
const BitVector<> &edges_mask,
int edges_num_active,
float epsilon,
int tree_type,
@ -872,7 +871,7 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BitSpan edges_mask,
const BitVector<> &edges_mask,
int edges_num_active,
float epsilon,
int tree_type,
@ -900,7 +899,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
const float (*vert_positions)[3],
const MEdge *edge,
const int edges_num,
const BitSpan edges_mask,
const BitVector<> &edges_mask,
int edges_num_active,
float epsilon,
int tree_type,
@ -932,7 +931,7 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
const float (*positions)[3],
const MFace *face,
const int faces_num,
const BitSpan faces_mask,
const BitVector<> &faces_mask,
int faces_num_active)
{
if (faces_num == 0) {
@ -985,7 +984,7 @@ static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
int tree_type,
int axis,
BMEditMesh *em,
const BitSpan looptri_mask,
const BitVector<> &looptri_mask,
int looptri_num_active)
{
const int looptri_num = em->tottri;
@ -1039,7 +1038,7 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
const MLoop *mloop,
const MLoopTri *looptri,
const int looptri_num,
const BitSpan looptri_mask,
const BitVector<> &looptri_mask,
int looptri_num_active)
{
if (!looptri_mask.is_empty()) {
@ -1080,7 +1079,7 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BitSpan looptri_mask,
const BitVector<> &looptri_mask,
int looptri_num_active,
float epsilon,
int tree_type,
@ -1110,7 +1109,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
const int looptri_num,
const BitSpan looptri_mask,
const BitVector<> &looptri_mask,
int looptri_num_active,
float epsilon,
int tree_type,

View File

@ -2991,19 +2991,6 @@ 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;

View File

@ -557,11 +557,10 @@ int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[],
/* ...................................... */
/* Helper for calc_fcurve_* functions -> find first and last BezTriple to be used. */
static bool get_fcurve_end_keyframes(const FCurve *fcu,
BezTriple **first,
BezTriple **last,
const bool do_sel_only,
const float range[2])
static short get_fcurve_end_keyframes(const FCurve *fcu,
BezTriple **first,
BezTriple **last,
const bool do_sel_only)
{
bool found = false;
@ -574,31 +573,11 @@ static bool get_fcurve_end_keyframes(const FCurve *fcu,
return found;
}
int first_index = 0;
int last_index = fcu->totvert - 1;
if (range != NULL) {
/* If a range is passed in find the first and last keyframe within that range. */
bool replace = false;
first_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, range[0], fcu->totvert, &replace);
last_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, range[1], fcu->totvert, &replace);
/* If first and last index are the same, no keyframes were found in the range. */
if (first_index == last_index) {
return found;
}
/* The binary search returns an index where a keyframe would be inserted,
so it needs to be clamped to ensure it is in range of the array. */
first_index = clamp_i(first_index, 0, fcu->totvert - 1);
last_index = clamp_i(last_index - 1, 0, fcu->totvert - 1);
}
/* Only include selected items? */
if (do_sel_only) {
/* Find first selected. */
for (int i = first_index; i <= last_index; i++) {
BezTriple *bezt = &fcu->bezt[i];
BezTriple *bezt = fcu->bezt;
for (int i = 0; i < fcu->totvert; bezt++, i++) {
if (BEZT_ISSEL_ANY(bezt)) {
*first = bezt;
found = true;
@ -607,8 +586,8 @@ static bool get_fcurve_end_keyframes(const FCurve *fcu,
}
/* Find last selected. */
for (int i = last_index; i >= first_index; i--) {
BezTriple *bezt = &fcu->bezt[i];
bezt = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
for (int i = 0; i < fcu->totvert; bezt--, i++) {
if (BEZT_ISSEL_ANY(bezt)) {
*last = bezt;
found = true;
@ -617,8 +596,9 @@ static bool get_fcurve_end_keyframes(const FCurve *fcu,
}
}
else {
*first = &fcu->bezt[first_index];
*last = &fcu->bezt[last_index];
/* Use the whole array. */
*first = fcu->bezt;
*last = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
found = true;
}
@ -631,25 +611,23 @@ bool BKE_fcurve_calc_bounds(const FCurve *fcu,
float *ymin,
float *ymax,
const bool do_sel_only,
const bool include_handles,
const float range[2])
const bool include_handles)
{
float xminv = 999999999.0f, xmaxv = -999999999.0f;
float yminv = 999999999.0f, ymaxv = -999999999.0f;
bool foundvert = false;
const bool use_range = range != NULL;
if (fcu->totvert) {
if (fcu->bezt) {
BezTriple *bezt_first = NULL, *bezt_last = NULL;
if (xmin || xmax) {
BezTriple *bezt_first = NULL, *bezt_last = NULL;
foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only, range);
/* Get endpoint keyframes. */
foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only);
if (bezt_first) {
BLI_assert(bezt_last != NULL);
foundvert = true;
if (include_handles) {
xminv = min_fff(xminv, bezt_first->vec[0][0], bezt_first->vec[1][0]);
xmaxv = max_fff(xmaxv, bezt_last->vec[1][0], bezt_last->vec[2][0]);
@ -667,9 +645,6 @@ bool BKE_fcurve_calc_bounds(const FCurve *fcu,
int i;
for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) {
if (use_range && (bezt->vec[1][0] < range[0] || bezt->vec[1][0] > range[1])) {
continue;
}
if ((do_sel_only == false) || BEZT_ISSEL_ANY(bezt)) {
/* Keyframe itself. */
yminv = min_ff(yminv, bezt->vec[1][1]);
@ -742,10 +717,10 @@ bool BKE_fcurve_calc_bounds(const FCurve *fcu,
}
if (xmin) {
*xmin = use_range ? range[0] : 0.0f;
*xmin = 0.0f;
}
if (xmax) {
*xmax = use_range ? range[1] : 1.0f;
*xmax = 1.0f;
}
if (ymin) {
@ -770,7 +745,7 @@ bool BKE_fcurve_calc_range(
BezTriple *bezt_first = NULL, *bezt_last = NULL;
/* Get endpoint keyframes. */
get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only, NULL);
get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only);
if (bezt_first) {
BLI_assert(bezt_last != NULL);

View File

@ -375,6 +375,7 @@ 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>,
@ -386,6 +387,7 @@ 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>,
@ -397,6 +399,7 @@ 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>,
@ -408,6 +411,7 @@ 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>,
@ -419,6 +423,7 @@ 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>,
@ -430,6 +435,7 @@ 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>,
@ -447,6 +453,7 @@ 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>,
@ -459,6 +466,7 @@ 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>,
@ -471,6 +479,7 @@ 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>,
@ -486,6 +495,7 @@ 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>,
@ -504,6 +514,7 @@ 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>,
@ -522,6 +533,7 @@ 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>,
@ -540,6 +552,7 @@ 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>,
@ -556,6 +569,7 @@ 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>,
@ -568,6 +582,7 @@ 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, NonDeletable)
"position", ATTR_DOMAIN_INSTANCE, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable)
{
}
@ -200,6 +200,7 @@ 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,6 +1137,48 @@ 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.
@ -1180,17 +1222,21 @@ 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>,
@ -1209,6 +1255,7 @@ 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>,
@ -1222,6 +1269,7 @@ 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>,
@ -1233,6 +1281,7 @@ 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>,
@ -1245,6 +1294,7 @@ 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>,
@ -1258,7 +1308,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, &crease},
{&position, &id, &material_index, &shade_smooth, &sharp_edge, &normal, &crease},
{&corner_custom_data,
&vertex_groups,
&point_custom_data,

View File

@ -142,6 +142,7 @@ 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>,
@ -152,6 +153,7 @@ 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>,
@ -162,6 +164,7 @@ 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

@ -190,9 +190,6 @@ static int stroke_march_next_point(const bGPDstroke *gps,
float *pressure,
float *strength,
float *vert_color,
float *uv_fac,
float *uv_fill,
float *uv_rot,
float *ratio_result,
int *index_from,
int *index_to)
@ -274,10 +271,6 @@ static int stroke_march_next_point(const bGPDstroke *gps,
gps->points[next_point_index].pressure, gps->points[*index_from].pressure, vratio);
*strength = interpf(
gps->points[next_point_index].strength, gps->points[*index_from].strength, vratio);
*uv_fac = interpf(gps->points[next_point_index].uv_fac, gps->points[*index_from].uv_fac, vratio);
*uv_rot = interpf(gps->points[next_point_index].uv_rot, gps->points[*index_from].uv_rot, vratio);
interp_v2_v2v2(
uv_fill, gps->points[*index_from].uv_fill, gps->points[next_point_index].uv_fill, vratio);
interp_v4_v4v4(vert_color,
gps->points[*index_from].vert_color,
gps->points[next_point_index].vert_color,
@ -481,7 +474,6 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd,
int next_point_index = 1;
int i = 0;
float pressure, strength, ratio_result;
float uv_fac, uv_rot, uv_fill[2];
float vert_color[4];
int index_from, index_to;
float last_coord[3];
@ -512,9 +504,6 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd,
&pressure,
&strength,
vert_color,
&uv_fac,
uv_fill,
&uv_rot,
&ratio_result,
&index_from,
&index_to)) > -1) {
@ -525,10 +514,6 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd,
copy_v3_v3(&pt2->x, last_coord);
new_pt[i].pressure = pressure;
new_pt[i].strength = strength;
new_pt[i].uv_fac = uv_fac;
new_pt[i].uv_rot = uv_rot;
copy_v2_v2(new_pt[i].uv_fill, uv_fill);
memcpy(new_pt[i].vert_color, vert_color, sizeof(float[4]));
if (select) {
new_pt[i].flag |= GP_SPOINT_SELECT;

View File

@ -17,6 +17,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_bit_vector.hh"
#include "BLI_bounds.hh"
#include "BLI_edgehash.h"
#include "BLI_endian_switch.h"
@ -65,6 +66,7 @@
#include "BLO_read_write.h"
using blender::BitVector;
using blender::float3;
using blender::MutableSpan;
using blender::Span;

View File

@ -316,7 +316,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
BKE_mesh_vertex_normals_ensure(mesh) :
nullptr;
const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX));
const blender::BitSpan facedot_tags = mesh->runtime->subsurf_face_dot_tags;
const blender::BitVector<> &facedot_tags = mesh->runtime->subsurf_face_dot_tags;
if (index) {
for (int i = 0; i < mesh->totpoly; i++, mp++) {

View File

@ -42,7 +42,6 @@
using blender::BitVector;
using blender::float3;
using blender::int2;
using blender::MutableBitSpan;
using blender::MutableSpan;
using blender::short2;
using blender::Span;
@ -1239,7 +1238,7 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const Span<MLoop> mloop
const Span<int2> edge_to_loops,
const Span<int> loop_to_poly,
const int *e2l_prev,
MutableBitSpan skip_loops,
BitVector<> &skip_loops,
const int ml_curr_index,
const int ml_prev_index,
const int mp_curr_index)

View File

@ -91,7 +91,7 @@ void BKE_nlastrip_free(NlaStrip *strip, const bool do_id_user)
MEM_freeN(strip);
}
void BKE_nlatrack_free(NlaTrack *nlt, const bool do_id_user)
void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
{
NlaStrip *strip, *stripn;
@ -107,7 +107,12 @@ void BKE_nlatrack_free(NlaTrack *nlt, const bool do_id_user)
}
/* free NLA track itself now */
MEM_freeN(nlt);
if (tracks) {
BLI_freelinkN(tracks, nlt);
}
else {
MEM_freeN(nlt);
}
}
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
@ -122,7 +127,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_remove_and_free(tracks, nlt, do_id_user);
BKE_nlatrack_free(tracks, nlt, do_id_user);
}
/* clear the list's pointers to be safe */
@ -509,20 +514,6 @@ 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 */

View File

@ -77,43 +77,18 @@ TEST(nla_track, BKE_nlatrack_remove_strip)
strip2.start = 11;
strip2.end = 20;
/* Add NLA strips to the NLATrack. */
// 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. */
// 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. */
// 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

@ -2266,8 +2266,6 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
return pbvh;
}
ob->sculpt->islands_valid = false;
if (ob->sculpt->bm != nullptr) {
/* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
pbvh = build_pbvh_for_dynamic_topology(ob);

View File

@ -956,9 +956,7 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
const int xy[2])
{
LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
/* Test area's outer screen verts, not inner `area->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 (BLI_rcti_isect_pt_v(&area->totrct, xy)) {
if (ELEM(spacetype, SPACE_TYPE_ANY, area->spacetype)) {
return area;
}

View File

@ -1,234 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup bli
*
* This file provides the basis for processing "indexed bits" (i.e. every bit has an index).
* The main purpose of this file is to define how bits are indexed within a memory buffer.
* For example, one has to define whether the first bit is the least or most significant bit and
* how endianness affect the bit order.
*
* The order is defined as follows:
* - Every indexed bit is part of an #BitInt. These ints are ordered by their address as usual.
* - Within each #BitInt, the bits are ordered from least to most significant.
*/
#include "BLI_index_range.hh"
#include "BLI_utildefines.h"
#include <ostream>
namespace blender::bits {
/** Using a large integer type is better because then it's easier to process many bits at once. */
using BitInt = uint64_t;
/** Number of bits that fit into #BitInt. */
static constexpr int64_t BitsPerInt = int64_t(sizeof(BitInt) * 8);
/** Shift amount to get from a bit index to an int index. Equivalent to `log(BitsPerInt, 2)`. */
static constexpr int64_t BitToIntIndexShift = 3 + (sizeof(BitInt) >= 2) + (sizeof(BitInt) >= 4) +
(sizeof(BitInt) >= 8);
/** Bit mask containing a 1 for the last few bits that index a bit inside of an #BitInt. */
static constexpr BitInt BitIndexMask = (BitInt(1) << BitToIntIndexShift) - 1;
inline BitInt mask_first_n_bits(const int64_t n)
{
BLI_assert(n >= 0);
BLI_assert(n <= BitsPerInt);
if (n == BitsPerInt) {
return BitInt(-1);
}
return (BitInt(1) << n) - 1;
}
inline BitInt mask_last_n_bits(const int64_t n)
{
return ~mask_first_n_bits(BitsPerInt - n);
}
inline BitInt mask_range_bits(const int64_t start, const int64_t size)
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
const int64_t end = start + size;
BLI_assert(end <= BitsPerInt);
if (end == BitsPerInt) {
return mask_last_n_bits(size);
}
return ((BitInt(1) << end) - 1) & ~((BitInt(1) << start) - 1);
}
inline BitInt mask_single_bit(const int64_t bit_index)
{
BLI_assert(bit_index >= 0);
BLI_assert(bit_index < BitsPerInt);
return BitInt(1) << bit_index;
}
inline BitInt *int_containing_bit(BitInt *data, const int64_t bit_index)
{
return data + (bit_index >> BitToIntIndexShift);
}
inline const BitInt *int_containing_bit(const BitInt *data, const int64_t bit_index)
{
return data + (bit_index >> BitToIntIndexShift);
}
/**
* This is a read-only pointer to a specific bit. The value of the bit can be retrieved, but
* not changed.
*/
class BitRef {
private:
/** Points to the exact integer that the bit is in. */
const BitInt *int_;
/** All zeros except for a single one at the bit that is referenced. */
BitInt mask_;
friend class MutableBitRef;
public:
BitRef() = default;
/**
* Reference a specific bit in an array. Note that #data does *not* have to point to the
* exact integer the bit is in.
*/
BitRef(const BitInt *data, const int64_t bit_index)
{
int_ = int_containing_bit(data, bit_index);
mask_ = mask_single_bit(bit_index & BitIndexMask);
}
/**
* Return true when the bit is currently 1 and false otherwise.
*/
bool test() const
{
const BitInt value = *int_;
const BitInt masked_value = value & mask_;
return masked_value != 0;
}
operator bool() const
{
return this->test();
}
};
/**
* Similar to #BitRef, but also allows changing the referenced bit.
*/
class MutableBitRef {
private:
/** Points to the integer that the bit is in. */
BitInt *int_;
/** All zeros except for a single one at the bit that is referenced. */
BitInt mask_;
public:
MutableBitRef() = default;
/**
* Reference a specific bit in an array. Note that #data does *not* have to point to the
* exact int the bit is in.
*/
MutableBitRef(BitInt *data, const int64_t bit_index)
{
int_ = int_containing_bit(data, bit_index);
mask_ = mask_single_bit(bit_index & BitIndexMask);
}
/**
* Support implicitly casting to a read-only #BitRef.
*/
operator BitRef() const
{
BitRef bit_ref;
bit_ref.int_ = int_;
bit_ref.mask_ = mask_;
return bit_ref;
}
/**
* Return true when the bit is currently 1 and false otherwise.
*/
bool test() const
{
const BitInt value = *int_;
const BitInt masked_value = value & mask_;
return masked_value != 0;
}
operator bool() const
{
return this->test();
}
/**
* Change the bit to a 1.
*/
void set()
{
*int_ |= mask_;
}
/**
* Change the bit to a 0.
*/
void reset()
{
*int_ &= ~mask_;
}
/**
* Change the bit to a 1 if #value is true and 0 otherwise. If the value is highly unpredictable
* by the CPU branch predictor, it can be faster to use #set_branchless instead.
*/
void set(const bool value)
{
if (value) {
this->set();
}
else {
this->reset();
}
}
/**
* Does the same as #set, but does not use a branch. This is faster when the input value is
* unpredictable for the CPU branch predictor (best case for this function is a uniform random
* distribution with 50% probability for true and false). If the value is predictable, this is
* likely slower than #set.
*/
void set_branchless(const bool value)
{
const BitInt value_int = BitInt(value);
BLI_assert(ELEM(value_int, 0, 1));
const BitInt old = *int_;
*int_ =
/* Unset bit. */
(~mask_ & old)
/* Optionally set it again. The -1 turns a 1 into `0x00...` and a 0 into `0xff...`. */
| (mask_ & ~(value_int - 1));
}
};
inline std::ostream &operator<<(std::ostream &stream, const BitRef &bit)
{
return stream << (bit ? "1" : "0");
}
inline std::ostream &operator<<(std::ostream &stream, const MutableBitRef &bit)
{
return stream << BitRef(bit);
}
} // namespace blender::bits
namespace blender {
using bits::BitRef;
using bits::MutableBitRef;
} // namespace blender

View File

@ -1,290 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_bit_ref.hh"
#include "BLI_index_range.hh"
#include "BLI_memory_utils.hh"
namespace blender::bits {
/** Base class for a const and non-const bit-iterator. */
class BitIteratorBase {
protected:
const BitInt *data_;
int64_t bit_index_;
public:
BitIteratorBase(const BitInt *data, const int64_t bit_index) : data_(data), bit_index_(bit_index)
{
}
BitIteratorBase &operator++()
{
bit_index_++;
return *this;
}
friend bool operator!=(const BitIteratorBase &a, const BitIteratorBase &b)
{
BLI_assert(a.data_ == b.data_);
return a.bit_index_ != b.bit_index_;
}
};
/** Allows iterating over the bits in a memory buffer. */
class BitIterator : public BitIteratorBase {
public:
BitIterator(const BitInt *data, const int64_t bit_index) : BitIteratorBase(data, bit_index)
{
}
BitRef operator*() const
{
return BitRef(data_, bit_index_);
}
};
/** Allows iterating over the bits in a memory buffer. */
class MutableBitIterator : public BitIteratorBase {
public:
MutableBitIterator(BitInt *data, const int64_t bit_index) : BitIteratorBase(data, bit_index)
{
}
MutableBitRef operator*() const
{
return MutableBitRef(const_cast<BitInt *>(data_), bit_index_);
}
};
/**
* Similar to #Span, but references a range of bits instead of normal C++ types (which must be at
* least one byte large). Use #MutableBitSpan if the values are supposed to be modified.
*
* The beginning and end of a #BitSpan does *not* have to be at byte/int boundaries. It can start
* and end at any bit.
*/
class BitSpan {
private:
/** Base pointer to the integers containing the bits. The actual bit span might start at a much
* higher address when `bit_range_.start()` is large. */
const BitInt *data_ = nullptr;
/** The range of referenced bits. */
IndexRange bit_range_ = {0, 0};
public:
/** Construct an empty span. */
BitSpan() = default;
BitSpan(const BitInt *data, const int64_t size_in_bits) : data_(data), bit_range_(size_in_bits)
{
}
BitSpan(const BitInt *data, const IndexRange bit_range) : data_(data), bit_range_(bit_range)
{
}
/** Number of bits referenced by the span. */
int64_t size() const
{
return bit_range_.size();
}
bool is_empty() const
{
return bit_range_.is_empty();
}
IndexRange index_range() const
{
return IndexRange(bit_range_.size());
}
BitRef operator[](const int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < bit_range_.size());
return {data_, bit_range_.start() + index};
}
BitSpan slice(const IndexRange range) const
{
return {data_, bit_range_.slice(range)};
}
const BitInt *data() const
{
return data_;
}
const IndexRange &bit_range() const
{
return bit_range_;
}
BitIterator begin() const
{
return {data_, bit_range_.start()};
}
BitIterator end() const
{
return {data_, bit_range_.one_after_last()};
}
};
/** Same as #BitSpan, but also allows modifying the referenced bits. */
class MutableBitSpan {
private:
BitInt *data_ = nullptr;
IndexRange bit_range_ = {0, 0};
public:
MutableBitSpan() = default;
MutableBitSpan(BitInt *data, const int64_t size) : data_(data), bit_range_(size)
{
}
MutableBitSpan(BitInt *data, const IndexRange bit_range) : data_(data), bit_range_(bit_range)
{
}
int64_t size() const
{
return bit_range_.size();
}
bool is_empty() const
{
return bit_range_.is_empty();
}
IndexRange index_range() const
{
return IndexRange(bit_range_.size());
}
MutableBitRef operator[](const int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < bit_range_.size());
return {data_, bit_range_.start() + index};
}
MutableBitSpan slice(const IndexRange range) const
{
return {data_, bit_range_.slice(range)};
}
BitInt *data() const
{
return data_;
}
const IndexRange &bit_range() const
{
return bit_range_;
}
MutableBitIterator begin() const
{
return {data_, bit_range_.start()};
}
MutableBitIterator end() const
{
return {data_, bit_range_.one_after_last()};
}
operator BitSpan() const
{
return {data_, bit_range_};
}
/** Sets all referenced bits to 1. */
void set_all()
{
const AlignedIndexRanges ranges = split_index_range_by_alignment(bit_range_, BitsPerInt);
{
BitInt &first_int = *int_containing_bit(data_, bit_range_.start());
const BitInt first_int_mask = mask_range_bits(ranges.prefix.start() & BitIndexMask,
ranges.prefix.size());
first_int |= first_int_mask;
}
{
BitInt *start = int_containing_bit(data_, ranges.aligned.start());
const int64_t ints_to_fill = ranges.aligned.size() / BitsPerInt;
constexpr BitInt fill_value = BitInt(-1);
initialized_fill_n(start, ints_to_fill, fill_value);
}
{
BitInt &last_int = *int_containing_bit(data_, bit_range_.one_after_last() - 1);
const BitInt last_int_mask = mask_first_n_bits(ranges.suffix.size());
last_int |= last_int_mask;
}
}
/** Sets all referenced bits to 0. */
void reset_all()
{
const AlignedIndexRanges ranges = split_index_range_by_alignment(bit_range_, BitsPerInt);
{
BitInt &first_int = *int_containing_bit(data_, bit_range_.start());
const BitInt first_int_mask = mask_range_bits(ranges.prefix.start() & BitIndexMask,
ranges.prefix.size());
first_int &= ~first_int_mask;
}
{
BitInt *start = int_containing_bit(data_, ranges.aligned.start());
const int64_t ints_to_fill = ranges.aligned.size() / BitsPerInt;
constexpr BitInt fill_value = 0;
initialized_fill_n(start, ints_to_fill, fill_value);
}
{
BitInt &last_int = *int_containing_bit(data_, bit_range_.one_after_last() - 1);
const BitInt last_int_mask = mask_first_n_bits(ranges.suffix.size());
last_int &= ~last_int_mask;
}
}
/** Sets all referenced bits to either 0 or 1. */
void set_all(const bool value)
{
if (value) {
this->set_all();
}
else {
this->reset_all();
}
}
/** Same as #set_all to mirror #MutableSpan. */
void fill(const bool value)
{
this->set_all(value);
}
};
inline std::ostream &operator<<(std::ostream &stream, const BitSpan &span)
{
stream << "(Size: " << span.size() << ", ";
for (const BitRef bit : span) {
stream << bit;
}
stream << ")";
return stream;
}
inline std::ostream &operator<<(std::ostream &stream, const MutableBitSpan &span)
{
return stream << BitSpan(span);
}
} // namespace blender::bits
namespace blender {
using bits::BitSpan;
using bits::MutableBitSpan;
} // namespace blender

View File

@ -38,11 +38,142 @@
#include <cstring>
#include "BLI_allocator.hh"
#include "BLI_bit_span.hh"
#include "BLI_index_range.hh"
#include "BLI_memory_utils.hh"
#include "BLI_span.hh"
namespace blender::bits {
/**
* Using a large integer type is better because then it's easier to process many bits at once.
*/
using IntType = uint64_t;
static constexpr int64_t BitsPerInt = int64_t(sizeof(IntType) * 8);
static constexpr int64_t BitToIntIndexShift = 3 + (sizeof(IntType) >= 2) + (sizeof(IntType) >= 4) +
(sizeof(IntType) >= 8);
static constexpr IntType BitIndexMask = (IntType(1) << BitToIntIndexShift) - 1;
/**
* This is a read-only pointer to a specific bit. The value of the bit can be retrieved, but
* not changed.
*/
class BitRef {
private:
/** Points to the integer that the bit is in. */
const IntType *ptr_;
/** All zeros except for a single one at the bit that is referenced. */
IntType mask_;
friend class MutableBitRef;
public:
BitRef() = default;
/**
* Reference a specific bit in an array. Note that #ptr does *not* have to point to the
* exact integer the bit is in.
*/
BitRef(const IntType *ptr, const int64_t bit_index)
{
ptr_ = ptr + (bit_index >> BitToIntIndexShift);
mask_ = IntType(1) << (bit_index & BitIndexMask);
}
/**
* Return true when the bit is currently 1 and false otherwise.
*/
bool test() const
{
const IntType value = *ptr_;
const IntType masked_value = value & mask_;
return masked_value != 0;
}
operator bool() const
{
return this->test();
}
};
/**
* Similar to #BitRef, but also allows changing the referenced bit.
*/
class MutableBitRef {
private:
/** Points to the integer that the bit is in. */
IntType *ptr_;
/** All zeros except for a single one at the bit that is referenced. */
IntType mask_;
public:
MutableBitRef() = default;
/**
* Reference a specific bit in an array. Note that #ptr does *not* have to point to the
* exact int the bit is in.
*/
MutableBitRef(IntType *ptr, const int64_t bit_index)
{
ptr_ = ptr + (bit_index >> BitToIntIndexShift);
mask_ = IntType(1) << IntType(bit_index & BitIndexMask);
}
/**
* Support implicitly casting to a read-only #BitRef.
*/
operator BitRef() const
{
BitRef bit_ref;
bit_ref.ptr_ = ptr_;
bit_ref.mask_ = mask_;
return bit_ref;
}
/**
* Return true when the bit is currently 1 and false otherwise.
*/
bool test() const
{
const IntType value = *ptr_;
const IntType masked_value = value & mask_;
return masked_value != 0;
}
operator bool() const
{
return this->test();
}
/**
* Change the bit to a 1.
*/
void set()
{
*ptr_ |= mask_;
}
/**
* Change the bit to a 0.
*/
void reset()
{
*ptr_ &= ~mask_;
}
/**
* Change the bit to a 1 if #value is true and 0 otherwise.
*/
void set(const bool value)
{
if (value) {
this->set();
}
else {
this->reset();
}
}
};
template<
/**
* Number of bits that can be stored in the vector without doing an allocation.
@ -62,13 +193,13 @@ class BitVector {
static constexpr int64_t IntsInInlineBuffer = required_ints_for_bits(InlineBufferCapacity);
static constexpr int64_t BitsInInlineBuffer = IntsInInlineBuffer * BitsPerInt;
static constexpr int64_t AllocationAlignment = alignof(BitInt);
static constexpr int64_t AllocationAlignment = alignof(IntType);
/**
* Points to the first integer used by the vector. It might point to the memory in the inline
* buffer.
*/
BitInt *data_;
IntType *data_;
/** Current size of the vector in bits. */
int64_t size_in_bits_;
@ -80,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<BitInt, IntsInInlineBuffer> inline_buffer_;
BLI_NO_UNIQUE_ADDRESS TypedBuffer<IntType, IntsInInlineBuffer> inline_buffer_;
public:
BitVector(Allocator allocator = {}) noexcept : allocator_(allocator)
@ -88,7 +219,7 @@ class BitVector {
data_ = inline_buffer_;
size_in_bits_ = 0;
capacity_in_bits_ = BitsInInlineBuffer;
uninitialized_fill_n(data_, IntsInInlineBuffer, BitInt(0));
uninitialized_fill_n(data_, IntsInInlineBuffer, IntType(0));
}
BitVector(NoExceptConstructor, Allocator allocator = {}) noexcept : BitVector(allocator)
@ -105,8 +236,8 @@ class BitVector {
}
else {
/* Allocate a new array because the inline buffer is too small. */
data_ = static_cast<BitInt *>(
allocator_.allocate(ints_to_copy * sizeof(BitInt), AllocationAlignment, __func__));
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_;
@ -172,16 +303,6 @@ class BitVector {
return move_assign_container(*this, std::move(other));
}
operator BitSpan() const
{
return {data_, IndexRange(size_in_bits_)};
}
operator MutableBitSpan()
{
return {data_, IndexRange(size_in_bits_)};
}
/**
* Number of bits in the bit vector.
*/
@ -231,24 +352,80 @@ class BitVector {
size_in_bits_++;
}
BitIterator begin() const
class Iterator {
private:
const BitVector *vector_;
int64_t index_;
public:
Iterator(const BitVector &vector, const int64_t index) : vector_(&vector), index_(index)
{
}
Iterator &operator++()
{
index_++;
return *this;
}
friend bool operator!=(const Iterator &a, const Iterator &b)
{
BLI_assert(a.vector_ == b.vector_);
return a.index_ != b.index_;
}
BitRef operator*() const
{
return (*vector_)[index_];
}
};
class MutableIterator {
private:
BitVector *vector_;
int64_t index_;
public:
MutableIterator(BitVector &vector, const int64_t index) : vector_(&vector), index_(index)
{
}
MutableIterator &operator++()
{
index_++;
return *this;
}
friend bool operator!=(const MutableIterator &a, const MutableIterator &b)
{
BLI_assert(a.vector_ == b.vector_);
return a.index_ != b.index_;
}
MutableBitRef operator*() const
{
return (*vector_)[index_];
}
};
Iterator begin() const
{
return {data_, 0};
return {*this, 0};
}
BitIterator end() const
Iterator end() const
{
return {data_, size_in_bits_};
return {*this, size_in_bits_};
}
MutableBitIterator begin()
MutableIterator begin()
{
return {data_, 0};
return {*this, 0};
}
MutableBitIterator end()
MutableIterator end()
{
return {data_, size_in_bits_};
return {*this, size_in_bits_};
}
/**
@ -264,8 +441,31 @@ class BitVector {
}
size_in_bits_ = new_size_in_bits;
if (old_size_in_bits < new_size_in_bits) {
MutableBitSpan(data_, IndexRange(old_size_in_bits, new_size_in_bits - old_size_in_bits))
.set_all(value);
this->fill_range(IndexRange(old_size_in_bits, new_size_in_bits - old_size_in_bits), value);
}
}
/**
* Set #value for every element in #range.
*/
void fill_range(const IndexRange range, const bool value)
{
const AlignedIndexRanges aligned_ranges = split_index_range_by_alignment(range, BitsPerInt);
/* Fill first few bits. */
for (const int64_t i : aligned_ranges.prefix) {
(*this)[i].set(value);
}
/* Fill entire ints at once. */
const int64_t start_fill_int_index = aligned_ranges.aligned.start() / BitsPerInt;
const int64_t ints_to_fill = aligned_ranges.aligned.size() / BitsPerInt;
const IntType fill_value = value ? IntType(-1) : IntType(0);
initialized_fill_n(data_ + start_fill_int_index, ints_to_fill, fill_value);
/* Fill bits in the end that don't cover a full int. */
for (const int64_t i : aligned_ranges.suffix) {
(*this)[i].set(value);
}
}
@ -274,7 +474,7 @@ class BitVector {
*/
void fill(const bool value)
{
MutableBitSpan(data_, size_in_bits_).set_all(value);
this->fill_range(IndexRange(0, size_in_bits_), value);
}
/**
@ -317,7 +517,7 @@ class BitVector {
}
BLI_NOINLINE void realloc_to_at_least(const int64_t min_capacity_in_bits,
const BitInt initial_value_for_new_ints = 0)
const IntType initial_value_for_new_ints = 0x00)
{
if (capacity_in_bits_ >= min_capacity_in_bits) {
return;
@ -331,8 +531,8 @@ class BitVector {
const int64_t new_capacity_in_ints = std::max(min_capacity_in_ints, min_new_capacity_in_ints);
const int64_t ints_to_copy = this->used_ints_amount();
BitInt *new_data = static_cast<BitInt *>(
allocator_.allocate(new_capacity_in_ints * sizeof(BitInt), AllocationAlignment, __func__));
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
@ -362,5 +562,7 @@ class BitVector {
} // namespace blender::bits
namespace blender {
using bits::BitRef;
using bits::BitVector;
using bits::MutableBitRef;
} // namespace blender

View File

@ -304,13 +304,6 @@ void rotate_eul(float beul[3], char axis, float angle);
/* Order independent. */
/**
* Manipulate `eul` so it's close to `oldrot` while representing the same rotation
* with the aim of having the minimum difference between all axes.
*
* This is typically done so interpolating the values between two euler rotations
* doesn't add undesired rotation (even rotating multiple times around one axis).
*/
void compatible_eul(float eul[3], const float oldrot[3]);
void add_eul_euleul(float r_eul[3], float a[3], float b[3], short order);

View File

@ -457,8 +457,6 @@ if(WITH_GTESTS)
tests/BLI_array_store_test.cc
tests/BLI_array_test.cc
tests/BLI_array_utils_test.cc
tests/BLI_bit_ref_test.cc
tests/BLI_bit_span_test.cc
tests/BLI_bit_vector_test.cc
tests/BLI_bitmap_test.cc
tests/BLI_bounds_test.cc

View File

@ -1490,18 +1490,15 @@ void rotate_eul(float beul[3], const char axis, const float angle)
void compatible_eul(float eul[3], const float oldrot[3])
{
/* When the rotation exceeds 180 degrees, it can be wrapped by 360 degrees
* to produce a closer match.
* NOTE: Values between `pi` & `2 * pi` work, where `pi` has the lowest number of
* discontinuities and values approaching `2 * pi` center the resulting rotation around zero,
* at the expense of the result being less compatible, see !104856. */
const float pi_thresh = (float)M_PI;
/* we could use M_PI as pi_thresh: which is correct but 5.1 gives better results.
* Checked with baking actions to fcurves - campbell */
const float pi_thresh = (5.1f);
const float pi_x2 = (2.0f * (float)M_PI);
float deul[3];
uint i;
/* Correct differences around 360 degrees first. */
/* correct differences of about 360 degrees first */
for (i = 0; i < 3; i++) {
deul[i] = eul[i] - oldrot[i];
if (deul[i] > pi_thresh) {
@ -1514,17 +1511,29 @@ void compatible_eul(float eul[3], const float oldrot[3])
}
}
uint j = 1, k = 2;
for (i = 0; i < 3; j = k, k = i++) {
/* Check if this axis of rotations larger than 180 degrees and
* the others are smaller than 90 degrees. */
if (fabsf(deul[i]) > M_PI && fabsf(deul[j]) < M_PI_2 && fabsf(deul[k]) < M_PI_2) {
if (deul[i] > 0.0f) {
eul[i] -= pi_x2;
}
else {
eul[i] += pi_x2;
}
/* is 1 of the axis rotations larger than 180 degrees and the other small? NO ELSE IF!! */
if (fabsf(deul[0]) > 3.2f && fabsf(deul[1]) < 1.6f && fabsf(deul[2]) < 1.6f) {
if (deul[0] > 0.0f) {
eul[0] -= pi_x2;
}
else {
eul[0] += pi_x2;
}
}
if (fabsf(deul[1]) > 3.2f && fabsf(deul[2]) < 1.6f && fabsf(deul[0]) < 1.6f) {
if (deul[1] > 0.0f) {
eul[1] -= pi_x2;
}
else {
eul[1] += pi_x2;
}
}
if (fabsf(deul[2]) > 3.2f && fabsf(deul[0]) < 1.6f && fabsf(deul[1]) < 1.6f) {
if (deul[2] > 0.0f) {
eul[2] -= pi_x2;
}
else {
eul[2] += pi_x2;
}
}
}

View File

@ -1,160 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0 */
#include <array>
#include "BLI_bit_ref.hh"
#include "testing/testing.h"
namespace blender::bits::tests {
TEST(bit_ref, MaskFirstNBits)
{
EXPECT_EQ(mask_first_n_bits(0), 0);
EXPECT_EQ(mask_first_n_bits(1),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0001);
EXPECT_EQ(mask_first_n_bits(5),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0001'1111);
EXPECT_EQ(mask_first_n_bits(63),
0b0111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111);
EXPECT_EQ(mask_first_n_bits(64),
0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111);
}
TEST(bit_ref, MaskLastNBits)
{
EXPECT_EQ(mask_last_n_bits(0),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
EXPECT_EQ(mask_last_n_bits(1),
0b1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
EXPECT_EQ(mask_last_n_bits(5),
0b1111'1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
EXPECT_EQ(mask_last_n_bits(63),
0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1110);
EXPECT_EQ(mask_last_n_bits(64),
0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111);
}
TEST(bit_ref, MaskSingleBit)
{
EXPECT_EQ(mask_single_bit(0), 1);
EXPECT_EQ(mask_single_bit(1),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0010);
EXPECT_EQ(mask_single_bit(5),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0010'0000);
EXPECT_EQ(mask_single_bit(63),
0b1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
}
TEST(bit_ref, IntContainingBit)
{
std::array<uint64_t, 5> array;
uint64_t *data = array.data();
EXPECT_EQ(int_containing_bit(data, 0), data);
EXPECT_EQ(int_containing_bit(data, 1), data);
EXPECT_EQ(int_containing_bit(data, 63), data);
EXPECT_EQ(int_containing_bit(data, 64), data + 1);
EXPECT_EQ(int_containing_bit(data, 65), data + 1);
EXPECT_EQ(int_containing_bit(data, 100), data + 1);
EXPECT_EQ(int_containing_bit(data, 127), data + 1);
EXPECT_EQ(int_containing_bit(data, 128), data + 2);
const uint64_t *data_const = data;
EXPECT_EQ(int_containing_bit(data_const, 0), data_const);
EXPECT_EQ(int_containing_bit(data_const, 1), data_const);
EXPECT_EQ(int_containing_bit(data_const, 63), data_const);
EXPECT_EQ(int_containing_bit(data_const, 64), data_const + 1);
EXPECT_EQ(int_containing_bit(data_const, 65), data_const + 1);
EXPECT_EQ(int_containing_bit(data_const, 100), data_const + 1);
EXPECT_EQ(int_containing_bit(data_const, 127), data_const + 1);
EXPECT_EQ(int_containing_bit(data_const, 128), data_const + 2);
}
TEST(bit_ref, Test)
{
uint64_t data = (1 << 3) | (1 << 7);
EXPECT_FALSE(BitRef(&data, 0).test());
EXPECT_FALSE(BitRef(&data, 1).test());
EXPECT_FALSE(BitRef(&data, 2).test());
EXPECT_TRUE(BitRef(&data, 3).test());
EXPECT_FALSE(BitRef(&data, 4));
EXPECT_FALSE(BitRef(&data, 5));
EXPECT_FALSE(BitRef(&data, 6));
EXPECT_TRUE(BitRef(&data, 7));
EXPECT_FALSE(MutableBitRef(&data, 0).test());
EXPECT_FALSE(MutableBitRef(&data, 1).test());
EXPECT_FALSE(MutableBitRef(&data, 2).test());
EXPECT_TRUE(MutableBitRef(&data, 3).test());
EXPECT_FALSE(MutableBitRef(&data, 4));
EXPECT_FALSE(MutableBitRef(&data, 5));
EXPECT_FALSE(MutableBitRef(&data, 6));
EXPECT_TRUE(MutableBitRef(&data, 7));
}
TEST(bit_ref, Set)
{
uint64_t data = 0;
MutableBitRef(&data, 0).set();
MutableBitRef(&data, 1).set();
MutableBitRef(&data, 1).set();
MutableBitRef(&data, 4).set();
EXPECT_EQ(data, (1 << 0) | (1 << 1) | (1 << 4));
MutableBitRef(&data, 5).set(true);
MutableBitRef(&data, 1).set(false);
EXPECT_EQ(data, (1 << 0) | (1 << 4) | (1 << 5));
}
TEST(bit_ref, Reset)
{
uint64_t data = -1;
MutableBitRef(&data, 0).reset();
MutableBitRef(&data, 2).reset();
EXPECT_EQ(data, uint64_t(-1) & ~(1 << 0) & ~(1 << 2));
}
TEST(bit_ref, SetBranchless)
{
uint64_t data = 0;
MutableBitRef(&data, 0).set_branchless(true);
EXPECT_EQ(data, 1);
MutableBitRef(&data, 0).set_branchless(false);
EXPECT_EQ(data, 0);
MutableBitRef(&data, 3).set_branchless(false);
MutableBitRef(&data, 4).set_branchless(true);
EXPECT_EQ(data, 16);
MutableBitRef(&data, 3).set_branchless(true);
MutableBitRef(&data, 4).set_branchless(true);
EXPECT_EQ(data, 24);
}
TEST(bit_ref, Cast)
{
uint64_t data = 0;
MutableBitRef mutable_ref(&data, 3);
BitRef ref = mutable_ref;
EXPECT_FALSE(ref);
mutable_ref.set();
EXPECT_TRUE(ref);
}
TEST(bit_ref, MaskRangeBits)
{
EXPECT_EQ(mask_range_bits(0, 0),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
EXPECT_EQ(mask_range_bits(0, 1),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0001);
EXPECT_EQ(mask_range_bits(0, 5),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0001'1111);
EXPECT_EQ(mask_range_bits(64, 0),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
EXPECT_EQ(mask_range_bits(63, 1),
0b1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
EXPECT_EQ(mask_range_bits(59, 5),
0b1111'1000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
EXPECT_EQ(mask_range_bits(8, 3),
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0111'0000'0000);
EXPECT_EQ(mask_range_bits(0, 64),
0b1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111'1111);
}
} // namespace blender::bits::tests

View File

@ -1,139 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0 */
#include <array>
#include "BLI_bit_span.hh"
#include "testing/testing.h"
namespace blender::bits::tests {
TEST(bit_span, DefaultConstructor)
{
{
char buffer[sizeof(BitSpan)];
memset(buffer, 0xff, sizeof(BitSpan));
BitSpan &span = *new (buffer) BitSpan();
EXPECT_TRUE(span.is_empty());
EXPECT_EQ(span.size(), 0);
}
{
char buffer[sizeof(MutableBitSpan)];
memset(buffer, 0xff, sizeof(MutableBitSpan));
MutableBitSpan &span = *new (buffer) MutableBitSpan();
EXPECT_TRUE(span.is_empty());
EXPECT_EQ(span.size(), 0);
}
}
TEST(bit_span, Iteration)
{
uint64_t data = (1 << 2) | (1 << 3);
const BitSpan span(&data, 30);
EXPECT_EQ(span.size(), 30);
int index = 0;
for (const BitRef bit : span) {
EXPECT_EQ(bit.test(), ELEM(index, 2, 3));
index++;
}
}
TEST(bit_span, MutableIteration)
{
uint64_t data = 0;
MutableBitSpan span(&data, 40);
EXPECT_EQ(span.size(), 40);
int index = 0;
for (MutableBitRef bit : span) {
bit.set(index % 4 == 0);
index++;
}
EXPECT_EQ(data,
0b0000'0000'0000'0000'0000'0000'0001'0001'0001'0001'0001'0001'0001'0001'0001'0001);
}
TEST(bit_span, SubscriptOperator)
{
uint64_t data[2] = {0, 0};
MutableBitSpan mutable_span(data, 128);
BitSpan span = mutable_span;
EXPECT_EQ(mutable_span.data(), data);
EXPECT_EQ(mutable_span.bit_range(), IndexRange(128));
EXPECT_EQ(span.data(), data);
EXPECT_EQ(span.bit_range(), IndexRange(128));
EXPECT_FALSE(mutable_span[5].test());
EXPECT_FALSE(span[5].test());
mutable_span[5].set(5);
EXPECT_TRUE(mutable_span[5].test());
EXPECT_TRUE(span[5].test());
EXPECT_FALSE(mutable_span[120].test());
EXPECT_FALSE(span[120].test());
mutable_span[120].set(120);
EXPECT_TRUE(mutable_span[120].test());
EXPECT_TRUE(span[120].test());
EXPECT_EQ(data[0],
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0010'0000);
EXPECT_EQ(data[1],
0b0000'0001'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000);
}
TEST(bit_span, RangeConstructor)
{
uint64_t data = 0;
MutableBitSpan mutable_span(&data, IndexRange(4, 3));
BitSpan span = mutable_span;
EXPECT_FALSE(mutable_span[1].test());
EXPECT_FALSE(span[1].test());
mutable_span[0].set(true);
mutable_span[1].set(true);
mutable_span[2].set(true);
mutable_span[0].set(false);
mutable_span[2].set(false);
EXPECT_TRUE(mutable_span[1].test());
EXPECT_TRUE(span[1].test());
EXPECT_EQ(data,
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0010'0000);
}
TEST(bit_span, Set)
{
uint64_t data = 0;
MutableBitSpan(&data, 64).set_all(true);
EXPECT_EQ(data, uint64_t(-1));
MutableBitSpan(&data, 64).set_all(false);
EXPECT_EQ(data, uint64_t(0));
MutableBitSpan(&data, IndexRange(4, 8)).set_all(true);
EXPECT_EQ(data,
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111'1111'0000);
MutableBitSpan(&data, IndexRange(8, 30)).set_all(false);
EXPECT_EQ(data,
0b0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'0000'1111'0000);
}
TEST(bit_span, SetSliced)
{
std::array<uint64_t, 10> data;
memset(data.data(), 0, sizeof(data));
MutableBitSpan span{data.data(), 640};
span.slice(IndexRange(5, 500)).set_all(true);
for (const int64_t i : IndexRange(640)) {
EXPECT_EQ(span[i], i >= 5 && i < 505);
}
span.slice(IndexRange(10, 190)).set_all(false);
for (const int64_t i : IndexRange(640)) {
EXPECT_EQ(span[i], (i >= 5 && i < 10) || (i >= 200 && i < 505));
}
}
} // namespace blender::bits::tests

View File

@ -6,7 +6,7 @@
#include "testing/testing.h"
namespace blender::bits::tests {
namespace blender::tests {
TEST(bit_vector, DefaultConstructor)
{
@ -183,4 +183,4 @@ TEST(bit_vector, AppendMany)
EXPECT_TRUE(vec[5]);
}
} // namespace blender::bits::tests
} // namespace blender::tests

View File

@ -290,24 +290,6 @@ TEST(index_range, SplitByAlignment)
EXPECT_EQ(ranges.aligned, IndexRange());
EXPECT_EQ(ranges.suffix, IndexRange());
}
{
AlignedIndexRanges ranges = split_index_range_by_alignment(IndexRange(64), 64);
EXPECT_EQ(ranges.prefix, IndexRange());
EXPECT_EQ(ranges.aligned, IndexRange(64));
EXPECT_EQ(ranges.suffix, IndexRange());
}
{
AlignedIndexRanges ranges = split_index_range_by_alignment(IndexRange(64, 64), 64);
EXPECT_EQ(ranges.prefix, IndexRange());
EXPECT_EQ(ranges.aligned, IndexRange(64, 64));
EXPECT_EQ(ranges.suffix, IndexRange());
}
{
AlignedIndexRanges ranges = split_index_range_by_alignment(IndexRange(4, 8), 64);
EXPECT_EQ(ranges.prefix, IndexRange(4, 8));
EXPECT_EQ(ranges.aligned, IndexRange());
EXPECT_EQ(ranges.suffix, IndexRange());
}
}
} // namespace blender::tests

View File

@ -770,7 +770,11 @@ void blo_do_versions_userdef(UserDef *userdef)
/* Set GPU backend to OpenGL. */
if (!USER_VERSION_ATLEAST(305, 5)) {
#ifdef __APPLE__
userdef->gpu_backend = GPU_BACKEND_METAL;
#else
userdef->gpu_backend = GPU_BACKEND_OPENGL;
#endif
}
if (!USER_VERSION_ATLEAST(305, 10)) {

View File

@ -211,7 +211,7 @@ void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
int BM_iter_mesh_bitmap_from_filter(const char itype,
BMesh *bm,
blender::MutableBitSpan bitmap,
blender::BitVector<> &bitmap,
bool (*test_fn)(BMElem *, void *user_data),
void *user_data)
{
@ -234,7 +234,7 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
}
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
blender::MutableBitSpan bitmap,
blender::BitVector<> &bitmap,
bool (*test_fn)(BMFace *, void *user_data),
void *user_data)
{

View File

@ -21,7 +21,7 @@
#include "BLI_mempool.h"
#ifdef __cplusplus
# include "BLI_bit_span.hh"
# include "BLI_bit_vector.hh"
#endif
#ifdef __cplusplus
@ -228,14 +228,14 @@ void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
int BM_iter_mesh_bitmap_from_filter(char itype,
BMesh *bm,
blender::MutableBitSpan bitmap,
blender::BitVector<> &bitmap,
bool (*test_fn)(BMElem *, void *user_data),
void *user_data);
/**
* Needed when we want to check faces, but return a loop aligned array.
*/
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
blender::MutableBitSpan bitmap,
blender::BitVector<> &bitmap,
bool (*test_fn)(BMFace *, void *user_data),
void *user_data);

View File

@ -59,9 +59,9 @@ void main()
* IF PrimType == LineList: base_vertex_id = quad_id*2
* IF PrimType == LineStrip: base_vertex_id = quad_id
*
* NOTE: This is currently used as LineList.
* Note: This is currently used as LineList.
*
* NOTE: Primitive Restart Will not work with this setup as-is. We should avoid using
* Note: Primitive Restart Will not work with this setup as-is. We should avoid using
* input primitive types which use restart indices. */
int base_vertex_id = quad_id * 2;

View File

@ -557,7 +557,7 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
const bool mp_select = (efa) ? BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) : false;
if (mr->use_subsurf_fdots) {
const BitSpan facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const BitVector<> &facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const MLoop *mloop = mr->mloop;
const int ml_index_end = mp->loopstart + mp->totloop;

View File

@ -46,7 +46,7 @@ static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr,
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
if (mr->use_subsurf_fdots) {
const BitSpan facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const BitVector<> &facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const MLoop *mloop = mr->mloop;
const int ml_index_end = mp->loopstart + mp->totloop;

View File

@ -102,7 +102,7 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
void *_data)
{
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
const BitSpan optimal_display_edges = mr->me->runtime->subsurf_optimal_display_edges;
const BitVector<> &optimal_display_edges = mr->me->runtime->subsurf_optimal_display_edges;
const MLoop *mloop = mr->mloop;
const int ml_index_end = mp->loopstart + mp->totloop;

View File

@ -76,7 +76,7 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
zero_v3(co);
const MLoop *mloop = mr->mloop;
const BitSpan facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const BitVector<> &facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const int ml_index_end = mp->loopstart + mp->totloop;
for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {

View File

@ -74,7 +74,7 @@ static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr,
void *_data)
{
MeshExtract_FdotUV_Data *data = static_cast<MeshExtract_FdotUV_Data *>(_data);
const BitSpan facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const BitVector<> &facedot_tags = mr->me->runtime->subsurf_face_dot_tags;
const MLoop *mloop = mr->mloop;
const int ml_index_end = mp->loopstart + mp->totloop;

View File

@ -47,7 +47,6 @@
#include "ED_anim_api.h"
#include "ED_armature.h"
#include "ED_keyframes_edit.h" /* XXX move the select modes out of there! */
#include "ED_markers.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
@ -3639,283 +3638,6 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name View Channel Operator
* \{ */
static void get_normalized_fcurve_bounds(FCurve *fcu,
bAnimContext *ac,
const bAnimListElem *ale,
const bool include_handles,
const float range[2],
rctf *r_bounds)
{
const bool fcu_selection_only = false;
BKE_fcurve_calc_bounds(fcu,
&r_bounds->xmin,
&r_bounds->xmax,
&r_bounds->ymin,
&r_bounds->ymax,
fcu_selection_only,
include_handles,
range);
const short mapping_flag = ANIM_get_normalization_flags(ac);
const float min_height = 0.01f;
const float height = BLI_rctf_size_y(r_bounds);
if (height < min_height) {
r_bounds->ymin -= (min_height - height) / 2;
r_bounds->ymax += (min_height - height) / 2;
}
float offset;
const float unit_fac = ANIM_unit_mapping_get_factor(
ac->scene, ale->id, fcu, mapping_flag, &offset);
r_bounds->ymin = (r_bounds->ymin + offset) * unit_fac;
r_bounds->ymax = (r_bounds->ymax + offset) * unit_fac;
}
static void get_gpencil_bounds(bGPDlayer *gpl, const float range[2], rctf *r_bounds)
{
bool found_start = false;
int start_frame = 0;
int end_frame = 1;
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
if (gpf->framenum < range[0]) {
continue;
}
if (gpf->framenum > range[1]) {
break;
}
if (!found_start) {
start_frame = gpf->framenum;
found_start = true;
}
end_frame = gpf->framenum;
}
r_bounds->xmin = start_frame;
r_bounds->xmax = end_frame;
r_bounds->ymin = 0;
r_bounds->ymax = 1;
}
static bool get_channel_bounds(bAnimContext *ac,
bAnimListElem *ale,
const float range[2],
const bool include_handles,
rctf *r_bounds)
{
bool found_bounds = false;
switch (ale->datatype) {
case ALE_GPFRAME: {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
get_gpencil_bounds(gpl, range, r_bounds);
found_bounds = true;
break;
}
case ALE_FCURVE: {
FCurve *fcu = (FCurve *)ale->key_data;
get_normalized_fcurve_bounds(fcu, ac, ale, include_handles, range, r_bounds);
found_bounds = true;
break;
}
}
return found_bounds;
}
static void get_view_range(Scene *scene, const bool use_preview_range, float r_range[2])
{
if (use_preview_range && scene->r.flag & SCER_PRV_RANGE) {
r_range[0] = scene->r.psfra;
r_range[1] = scene->r.pefra;
}
else {
r_range[0] = -FLT_MAX;
r_range[1] = FLT_MAX;
}
}
/* Pad the given rctf with regions that could block the view.
* For example Markers and Time Scrubbing. */
static void add_region_padding(bContext *C, bAnimContext *ac, rctf *bounds)
{
BLI_rctf_scale(bounds, 1.1f);
const float pad_top = UI_TIME_SCRUB_MARGIN_Y;
const float pad_bottom = BLI_listbase_is_empty(ED_context_get_markers(C)) ?
V2D_SCROLL_HANDLE_HEIGHT :
UI_MARKER_MARGIN_Y;
BLI_rctf_pad_y(bounds, ac->region->winy, pad_bottom, pad_top);
}
/* Find the window region in the bAnimContext area and move it to bounds. */
static void move_graph_view(bContext *C, bAnimContext *ac, rctf *bounds, const int smooth_viewtx)
{
LISTBASE_FOREACH (ARegion *, region, &ac->area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
UI_view2d_smooth_view(C, region, bounds, smooth_viewtx);
}
}
}
static int graphkeys_view_selected_channels_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
/* Get editor data. */
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
}
ListBase anim_data = {NULL, NULL};
const int filter = (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_DATA_VISIBLE |
ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
size_t anim_data_length = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (anim_data_length == 0) {
WM_report(RPT_WARNING, "No channels to operate on");
return OPERATOR_CANCELLED;
}
float range[2];
const bool use_preview_range = RNA_boolean_get(op->ptr, "use_preview_range");
get_view_range(ac.scene, use_preview_range, range);
rctf bounds = {.xmin = FLT_MAX, .xmax = -FLT_MAX, .ymin = FLT_MAX, .ymax = -FLT_MAX};
bAnimListElem *ale;
const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
bool valid_bounds = false;
for (ale = anim_data.first; ale; ale = ale->next) {
rctf channel_bounds;
const bool found_bounds = get_channel_bounds(
&ac, ale, range, include_handles, &channel_bounds);
if (found_bounds) {
BLI_rctf_union(&bounds, &channel_bounds);
valid_bounds = true;
}
}
if (!valid_bounds) {
ANIM_animdata_freelist(&anim_data);
return OPERATOR_CANCELLED;
}
add_region_padding(C, &ac, &bounds);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
move_graph_view(C, &ac, &bounds, smooth_viewtx);
ANIM_animdata_freelist(&anim_data);
return OPERATOR_FINISHED;
}
static bool channel_view_poll(bContext *C)
{
return ED_operator_action_active(C) || ED_operator_graphedit_active(C);
}
static void ANIM_OT_channels_view_selected(wmOperatorType *ot)
{
/* Identifiers */
ot->name = "Frame Selected Channels";
ot->idname = "ANIM_OT_channels_view_selected";
ot->description = "Reset viewable area to show the selected channels";
/* API callbacks */
ot->exec = graphkeys_view_selected_channels_exec;
ot->poll = channel_view_poll;
ot->flag = 0;
ot->prop = RNA_def_boolean(ot->srna,
"include_handles",
true,
"Include Handles",
"Include handles of keyframes when calculating extents");
ot->prop = RNA_def_boolean(ot->srna,
"use_preview_range",
true,
"Use Preview Range",
"Ignore frames outside of the preview range");
}
static int graphkeys_channel_view_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
}
ListBase anim_data = {NULL, NULL};
const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS |
ANIMFILTER_LIST_CHANNELS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
bAnimListElem *ale;
const int channel_index = animchannels_channel_get(&ac, event->mval);
ale = BLI_findlink(&anim_data, channel_index);
if (ale == NULL) {
ANIM_animdata_freelist(&anim_data);
return OPERATOR_CANCELLED;
}
float range[2];
const bool use_preview_range = RNA_boolean_get(op->ptr, "use_preview_range");
get_view_range(ac.scene, use_preview_range, range);
rctf bounds;
const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
const bool found_bounds = get_channel_bounds(&ac, ale, range, include_handles, &bounds);
if (!found_bounds) {
ANIM_animdata_freelist(&anim_data);
return OPERATOR_CANCELLED;
}
add_region_padding(C, &ac, &bounds);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
move_graph_view(C, &ac, &bounds, smooth_viewtx);
ANIM_animdata_freelist(&anim_data);
return OPERATOR_FINISHED;
}
static void ANIM_OT_channel_view_pick(wmOperatorType *ot)
{
/* Identifiers */
ot->name = "Frame Channel Under Cursor";
ot->idname = "ANIM_OT_channel_view_pick";
ot->description = "Reset viewable area to show the channel under the cursor";
/* API callbacks */
ot->invoke = graphkeys_channel_view_pick_invoke;
ot->poll = channel_view_poll;
ot->flag = 0;
ot->prop = RNA_def_boolean(ot->srna,
"include_handles",
true,
"Include Handles",
"Include handles of keyframes when calculating extents");
ot->prop = RNA_def_boolean(ot->srna,
"use_preview_range",
true,
"Use Preview Range",
"Ignore frames outside of the preview range");
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Operator Registration
* \{ */
@ -3935,9 +3657,6 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_setting_disable);
WM_operatortype_append(ANIM_OT_channels_setting_toggle);
WM_operatortype_append(ANIM_OT_channel_view_pick);
WM_operatortype_append(ANIM_OT_channels_view_selected);
WM_operatortype_append(ANIM_OT_channels_delete);
/* XXX does this need to be a separate operator? */

View File

@ -77,7 +77,11 @@ const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(const bool
if (include_generated) {
const EnumPropertyItem generated_items[] = {
{ASSET_LIBRARY_ALL, "ALL", 0, "All", "Show assets from all of the listed asset libraries"},
{ASSET_LIBRARY_ALL,
"ALL",
ICON_BLANK1,
"All",
"Show assets from all of the listed asset libraries"},
RNA_ENUM_ITEM_SEPR,
{ASSET_LIBRARY_LOCAL,
"LOCAL",
@ -86,7 +90,7 @@ const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(const bool
"Show the assets currently available in this Blender session"},
{ASSET_LIBRARY_ESSENTIALS,
"ESSENTIALS",
0,
ICON_BLANK1,
"Essentials",
"Show the basic building blocks and utilities coming with Blender"},
{0, nullptr, 0, nullptr, nullptr},
@ -118,7 +122,7 @@ const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(const bool
const int enum_value = ED_asset_library_reference_to_enum_value(&library_reference);
/* Use library path as description, it's a nice hint for users. */
EnumPropertyItem tmp = {
enum_value, user_library->name, ICON_NONE, user_library->name, user_library->path};
enum_value, user_library->name, ICON_BLANK1, user_library->name, user_library->path};
RNA_enum_item_add(&item, &totitem, &tmp);
}

View File

@ -1008,60 +1008,6 @@ static void CURVES_OT_select_linked(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int select_more_exec(bContext *C, wmOperator * /*op*/)
{
VectorSet<Curves *> unique_curves = get_unique_editable_curves(*C);
for (Curves *curves_id : unique_curves) {
CurvesGeometry &curves = curves_id->geometry.wrap();
select_adjacent(curves, false);
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
* attribute for now. */
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
}
return OPERATOR_FINISHED;
}
static void CURVES_OT_select_more(wmOperatorType *ot)
{
ot->name = "Select More";
ot->idname = __func__;
ot->description = "Grow the selection by one point";
ot->exec = select_more_exec;
ot->poll = editable_curves_point_domain_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int select_less_exec(bContext *C, wmOperator * /*op*/)
{
VectorSet<Curves *> unique_curves = get_unique_editable_curves(*C);
for (Curves *curves_id : unique_curves) {
CurvesGeometry &curves = curves_id->geometry.wrap();
select_adjacent(curves, true);
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
* attribute for now. */
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
}
return OPERATOR_FINISHED;
}
static void CURVES_OT_select_less(wmOperatorType *ot)
{
ot->name = "Select Less";
ot->idname = __func__;
ot->description = "Shrink the selection by one point";
ot->exec = select_less_exec;
ot->poll = editable_curves_point_domain_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
namespace surface_set {
static bool surface_set_poll(bContext *C)
@ -1187,8 +1133,6 @@ void ED_operatortypes_curves()
WM_operatortype_append(CURVES_OT_select_random);
WM_operatortype_append(CURVES_OT_select_end);
WM_operatortype_append(CURVES_OT_select_linked);
WM_operatortype_append(CURVES_OT_select_more);
WM_operatortype_append(CURVES_OT_select_less);
WM_operatortype_append(CURVES_OT_surface_set);
WM_operatortype_append(CURVES_OT_delete);
}

View File

@ -267,85 +267,6 @@ void select_linked(bke::CurvesGeometry &curves)
selection.finish();
}
void select_adjacent(bke::CurvesGeometry &curves, const bool deselect)
{
const OffsetIndices points_by_curve = curves.points_by_curve();
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, ATTR_DOMAIN_POINT, CD_PROP_BOOL);
const VArray<bool> cyclic = curves.cyclic();
if (deselect) {
invert_selection(selection.span);
}
if (selection.span.type().is<bool>()) {
MutableSpan<bool> selection_typed = selection.span.typed<bool>();
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
for (const int curve_i : range) {
const IndexRange points = points_by_curve[curve_i];
/* Handle all cases in the forward direction. */
for (int point_i = points.first(); point_i < points.last(); point_i++) {
if (!selection_typed[point_i] && selection_typed[point_i + 1]) {
selection_typed[point_i] = true;
}
}
/* Handle all cases in the backwards direction. */
for (int point_i = points.last(); point_i > points.first(); point_i--) {
if (!selection_typed[point_i] && selection_typed[point_i - 1]) {
selection_typed[point_i] = true;
}
}
/* Handle cyclic curve case. */
if (cyclic[curve_i]) {
if (selection_typed[points.first()] != selection_typed[points.last()]) {
selection_typed[points.first()] = true;
selection_typed[points.last()] = true;
}
}
}
});
}
else if (selection.span.type().is<float>()) {
MutableSpan<float> selection_typed = selection.span.typed<float>();
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
for (const int curve_i : range) {
const IndexRange points = points_by_curve[curve_i];
/* Handle all cases in the forward direction. */
for (int point_i = points.first(); point_i < points.last(); point_i++) {
if ((selection_typed[point_i] == 0.0f) && (selection_typed[point_i + 1] > 0.0f)) {
selection_typed[point_i] = 1.0f;
}
}
/* Handle all cases in the backwards direction. */
for (int point_i = points.last(); point_i > points.first(); point_i--) {
if ((selection_typed[point_i] == 0.0f) && (selection_typed[point_i - 1] > 0.0f)) {
selection_typed[point_i] = 1.0f;
}
}
/* Handle cyclic curve case. */
if (cyclic[curve_i]) {
if (selection_typed[points.first()] != selection_typed[points.last()]) {
selection_typed[points.first()] = 1.0f;
selection_typed[points.last()] = 1.0f;
}
}
}
});
}
if (deselect) {
invert_selection(selection.span);
}
selection.finish();
}
void select_random(bke::CurvesGeometry &curves,
const eAttrDomain selection_domain,
uint32_t random_seed,

View File

@ -135,11 +135,6 @@ void select_ends(bke::CurvesGeometry &curves, int amount, bool end_points);
*/
void select_linked(bke::CurvesGeometry &curves);
/**
* (De)select all the adjacent points of the current selected points.
*/
void select_adjacent(bke::CurvesGeometry &curves, bool deselect);
/**
* Select random points or curves.
*

View File

@ -239,17 +239,6 @@ enum {
UI_BUT_OVERRIDDEN = 1u << 31u,
};
/** #uiBut.dragflag */
enum {
/** By default only the left part of a button triggers dragging. A questionable design to make
* the icon but not other parts of the button draggable. Set this flag so the entire button can
* be dragged. */
UI_BUT_DRAG_FULL_BUT = (1 << 0),
/* --- Internal flags. --- */
UI_BUT_DRAGPOIN_FREE = (1 << 1),
};
/* Default font size for normal text. */
#define UI_DEFAULT_TEXT_POINTS 11.0f
@ -892,9 +881,6 @@ bool UI_but_flag_is_set(uiBut *but, int flag);
void UI_but_drawflag_enable(uiBut *but, int flag);
void UI_but_drawflag_disable(uiBut *but, int flag);
void UI_but_dragflag_enable(uiBut *but, int flag);
void UI_but_dragflag_disable(uiBut *but, int flag);
void UI_but_disable(uiBut *but, const char *disabled_hint);
void UI_but_type_set_menu_from_pulldown(uiBut *but);
@ -1803,12 +1789,9 @@ void UI_but_drag_set_id(uiBut *but, struct ID *id);
/**
* Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
* Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
*
* Sets #UI_BUT_DRAG_FULL_BUT so the full button can be dragged.
*/
void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
/**
* Sets #UI_BUT_DRAG_FULL_BUT so the full button can be dragged.
* \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
*/
void UI_but_drag_set_asset(uiBut *but,
@ -1825,8 +1808,6 @@ void UI_but_drag_set_name(uiBut *but, const char *name);
* Value from button itself.
*/
void UI_but_drag_set_value(uiBut *but);
/** Sets #UI_BUT_DRAG_FULL_BUT so the full button can be dragged. */
void UI_but_drag_set_image(
uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free);

View File

@ -4224,10 +4224,6 @@ static uiBut *ui_def_but(uiBlock *block,
but->flag |= UI_BUT_UNDO;
}
if (ELEM(but->type, UI_BTYPE_COLOR)) {
but->dragflag |= UI_BUT_DRAG_FULL_BUT;
}
BLI_addtail(&block->buttons, but);
if (block->curlayout) {
@ -4291,7 +4287,6 @@ static void ui_def_but_rna__menu(bContext * /*C*/, uiLayout *layout, void *but_p
int totitems = 0;
int categories = 0;
int entries_nosepr_count = 0;
bool has_item_with_icon = false;
for (const EnumPropertyItem *item = item_array; item->identifier; item++, totitems++) {
if (!item->identifier[0]) {
/* inconsistent, but menus with categories do not look good flipped */
@ -4303,9 +4298,6 @@ static void ui_def_but_rna__menu(bContext * /*C*/, uiLayout *layout, void *but_p
/* We do not want simple separators in `entries_nosepr_count`. */
continue;
}
if (item->icon) {
has_item_with_icon = true;
}
entries_nosepr_count++;
}
@ -4410,18 +4402,11 @@ static void ui_def_but_rna__menu(bContext * /*C*/, uiLayout *layout, void *but_p
uiItemS(column);
}
else {
int icon = item->icon;
/* Use blank icon if there is none for this item (but for some other one) to make sure labels
* align. */
if (icon == ICON_NONE && has_item_with_icon) {
icon = ICON_BLANK1;
}
if (icon) {
if (item->icon) {
uiDefIconTextButI(block,
UI_BTYPE_BUT_MENU,
B_NOP,
icon,
item->icon,
item->name,
0,
0,
@ -4600,7 +4585,15 @@ static uiBut *ui_def_but_rna(uiBlock *block,
#endif
}
icon = item[i].icon;
/* #ICON_BLANK1 can be used to add padding of the size of an icon. This is fine to align
* multiple items within a menu, but not for the menu button that only shows the label then.
*/
if ((type == UI_BTYPE_MENU) && (item[i].icon == ICON_BLANK1)) {
icon = ICON_NONE;
}
else {
icon = item[i].icon;
}
}
else {
if (!str) {
@ -5894,16 +5887,6 @@ void UI_but_drawflag_disable(uiBut *but, int flag)
but->drawflag &= ~flag;
}
void UI_but_dragflag_enable(uiBut *but, int flag)
{
but->dragflag |= flag;
}
void UI_but_dragflag_disable(uiBut *but, int flag)
{
but->dragflag &= ~flag;
}
void UI_but_disable(uiBut *but, const char *disabled_hint)
{
UI_but_flag_enable(but, UI_BUT_DISABLED);

View File

@ -24,7 +24,6 @@ void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
{
but->imb = imb;
but->imb_scale = scale;
UI_but_dragflag_enable(but, UI_BUT_DRAG_FULL_BUT);
}
void UI_but_drag_set_asset(uiBut *but,

View File

@ -86,6 +86,11 @@ enum {
/* WARNING: rest of #uiBut.flag in UI_interface.h */
};
/** #uiBut.dragflag */
enum {
UI_BUT_DRAGPOIN_FREE = (1 << 0),
};
/** #uiBut.pie_dir */
enum RadialDirection {
UI_RADIAL_NONE = -1,

View File

@ -247,7 +247,7 @@ bool ui_but_contains_point_px_icon(const uiBut *but, ARegion *region, const wmEv
BLI_rcti_rctf_copy(&rect, &but->rect);
if (but->dragflag & UI_BUT_DRAG_FULL_BUT) {
if (but->imb || but->type == UI_BTYPE_COLOR) {
/* use button size itself */
}
else if (but->drawflag & UI_BUT_ICON_LEFT) {

View File

@ -92,9 +92,15 @@ void attribute_search_add_items(StringRefNull str,
StringSearch *search = BLI_string_search_new();
for (const GeometryAttributeInfo *item : infos) {
/* Don't show the legacy "normal" attribute. */
if (item->name == "normal" && item->domain == ATTR_DOMAIN_FACE) {
continue;
}
if (!bke::allow_procedural_attribute_access(item->name)) {
continue;
}
BLI_string_search_add(search, item->name.c_str(), (void *)item, 0);
}

View File

@ -285,7 +285,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
params.add_solidify = RNA_boolean_get(op->ptr, "add_solidify");
/* Push an undo step prior to extraction.
* NOTE: A second push happens after the operator due to
* Note: A second push happens after the operator due to
* the OPTYPE_UNDO flag; having an initial undo step here
* is just needed to preserve the active object pointer.
*

View File

@ -83,7 +83,7 @@ bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br)
{
if (ss && br && SCULPT_stroke_is_dynamic_topology(ss, br)) {
if (br && SCULPT_stroke_is_dynamic_topology(ss, br)) {
return false;
}
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_TOPOLOGY)) {

View File

@ -1571,13 +1571,8 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
SCULPT_stroke_id_next(ob);
SCULPT_undo_push_begin(ob, op);
SCULPT_filter_cache_init(C,
ob,
sd,
SCULPT_UNDO_COORDS,
event->mval,
RNA_float_get(op->ptr, "area_normal_radius"),
RNA_float_get(op->ptr, "strength"));
SCULPT_filter_cache_init(
C, ob, sd, SCULPT_UNDO_COORDS, event->mval, RNA_float_get(op->ptr, "area_normal_radius"));
ss->filter_cache->automasking = SCULPT_automasking_cache_init(sd, nullptr, ob);

View File

@ -347,13 +347,8 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
SCULPT_filter_cache_init(C,
ob,
sd,
SCULPT_UNDO_COLOR,
event->mval,
RNA_float_get(op->ptr, "area_normal_radius"),
RNA_float_get(op->ptr, "strength"));
SCULPT_filter_cache_init(
C, ob, sd, SCULPT_UNDO_COLOR, event->mval, RNA_float_get(op->ptr, "area_normal_radius"));
FilterCache *filter_cache = ss->filter_cache;
filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
filter_cache->automasking = SCULPT_automasking_cache_init(sd, nullptr, ob);

View File

@ -8,9 +8,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_hash.h"
#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_math_vector_types.hh"
#include "BLI_task.h"
#include "DNA_meshdata_types.h"
@ -25,7 +23,6 @@
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "paint_intern.h"
@ -33,20 +30,14 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_prototypes.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "bmesh.h"
#include <cmath>
#include <cstdlib>
using blender::float2;
using blender::float3;
using blender::IndexRange;
void SCULPT_filter_to_orientation_space(float r_v[3], FilterCache *filter_cache)
{
switch (filter_cache->orientation) {
@ -105,14 +96,13 @@ void SCULPT_filter_cache_init(bContext *C,
Sculpt *sd,
const int undo_type,
const int mval[2],
float area_normal_radius,
float start_strength)
float area_normal_radius)
{
SculptSession *ss = ob->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
ss->filter_cache = MEM_cnew<FilterCache>(__func__);
ss->filter_cache->start_filter_strength = start_strength;
ss->filter_cache->random_seed = rand();
if (undo_type == SCULPT_UNDO_COLOR) {
@ -348,15 +338,6 @@ static bool sculpt_mesh_filter_needs_pmap(eSculptMeshFilterType filter_type)
MESH_FILTER_SHARPEN);
}
static bool sculpt_mesh_filter_is_continuous(eSculptMeshFilterType type)
{
return (ELEM(type,
MESH_FILTER_SHARPEN,
MESH_FILTER_SMOOTH,
MESH_FILTER_RELAX,
MESH_FILTER_RELAX_FACE_SETS));
}
static void mesh_filter_task_cb(void *__restrict userdata,
const int i,
const TaskParallelTLS *__restrict /*tls*/)
@ -398,8 +379,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
continue;
}
if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS) ||
ss->filter_cache->no_orig_co) {
if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
copy_v3_v3(orig_co, vd.co);
}
else {
@ -701,16 +681,34 @@ static void mesh_filter_surface_smooth_displace_task_cb(void *__restrict userdat
BKE_pbvh_vertex_iter_end;
}
static void sculpt_mesh_filter_apply(bContext *C, wmOperator *op)
static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = CTX_data_active_object(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
eSculptMeshFilterType filter_type = eSculptMeshFilterType(RNA_enum_get(op->ptr, "type"));
float filter_strength = RNA_float_get(op->ptr, "strength");
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
SCULPT_filter_cache_free(ss);
SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
return OPERATOR_FINISHED;
}
if (event->type != MOUSEMOVE) {
return OPERATOR_RUNNING_MODAL;
}
const float len = event->prev_press_xy[0] - event->xy[0];
filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
SCULPT_vertex_random_access_ensure(ss);
bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type);
BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false, false);
SculptThreadedTaskData data{};
data.sd = sd;
data.ob = ob;
@ -742,136 +740,22 @@ static void sculpt_mesh_filter_apply(bContext *C, wmOperator *op)
}
SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
}
static void sculpt_mesh_update_strength(wmOperator *op,
SculptSession *ss,
float2 prev_press_mouse,
float2 mouse)
{
const float len = prev_press_mouse[0] - mouse[0];
float filter_strength = ss->filter_cache->start_filter_strength * -len * 0.001f * UI_DPI_FAC;
RNA_float_set(op->ptr, "strength", filter_strength);
}
static void sculpt_mesh_filter_apply_with_history(bContext *C, wmOperator *op)
{
/* Event history is only stored for smooth and relax filters. */
if (!RNA_collection_length(op->ptr, "event_history")) {
sculpt_mesh_filter_apply(C, op);
return;
}
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
float2 start_mouse;
bool first = true;
float initial_strength = ss->filter_cache->start_filter_strength;
RNA_BEGIN (op->ptr, item, "event_history") {
float2 mouse;
RNA_float_get_array(&item, "mouse_event", mouse);
if (first) {
first = false;
start_mouse = mouse;
continue;
}
sculpt_mesh_update_strength(op, ss, start_mouse, mouse);
sculpt_mesh_filter_apply(C, op);
}
RNA_END;
RNA_float_set(op->ptr, "strength", initial_strength);
}
static void sculpt_mesh_filter_end(bContext *C, wmOperator * /*op*/)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
SCULPT_filter_cache_free(ss);
SCULPT_undo_push_end(ob);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
}
static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = CTX_data_active_object(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
SculptSession *ss = ob->sculpt;
const eSculptMeshFilterType filter_type = eSculptMeshFilterType(RNA_enum_get(op->ptr, "type"));
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
float initial_strength = ss->filter_cache->start_filter_strength;
sculpt_mesh_filter_end(C, op);
/* Don't update strength property if we're storing an event history. */
if (sculpt_mesh_filter_is_continuous(filter_type)) {
RNA_float_set(op->ptr, "strength", initial_strength);
}
return OPERATOR_FINISHED;
}
if (event->type != MOUSEMOVE) {
return OPERATOR_RUNNING_MODAL;
}
/* Note: some filter types are continuous, for these we store an
* event history in RNA for continuous.
* This way the user can tweak the last operator properties
* or repeat the op and get expected results. */
if (sculpt_mesh_filter_is_continuous(filter_type)) {
if (RNA_collection_length(op->ptr, "event_history") == 0) {
/* First entry is the start mouse position, event->prev_press_xy. */
PointerRNA startptr;
RNA_collection_add(op->ptr, "event_history", &startptr);
float2 mouse_start(float(event->prev_press_xy[0]), float(event->prev_press_xy[1]));
RNA_float_set_array(&startptr, "mouse_event", mouse_start);
}
PointerRNA itemptr;
RNA_collection_add(op->ptr, "event_history", &itemptr);
float2 mouse(float(event->xy[0]), float(event->xy[1]));
RNA_float_set_array(&itemptr, "mouse_event", mouse);
RNA_float_set(&itemptr, "pressure", WM_event_tablet_data(event, nullptr, nullptr));
}
float2 prev_mval(float(event->prev_press_xy[0]), float(event->prev_press_xy[1]));
float2 mval(float(event->xy[0]), float(event->xy[1]));
sculpt_mesh_update_strength(op, ss, prev_mval, mval);
bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type);
BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false, false);
sculpt_mesh_filter_apply(C, op);
return OPERATOR_RUNNING_MODAL;
}
/* Returns OPERATOR_PASS_THROUGH on success. */
static int sculpt_mesh_filter_start(bContext *C, wmOperator *op)
static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = CTX_data_active_object(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
int mval[2];
RNA_int_get_array(op->ptr, "start_mouse", mval);
const eSculptMeshFilterType filter_type = eSculptMeshFilterType(RNA_enum_get(op->ptr, "type"));
const bool use_automasking = SCULPT_is_automasking_enabled(sd, nullptr, nullptr);
const bool needs_topology_info = sculpt_mesh_filter_needs_pmap(filter_type) || use_automasking;
BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_topology_info, false, false);
SculptSession *ss = ob->sculpt;
const eMeshFilterDeformAxis deform_axis = eMeshFilterDeformAxis(
RNA_enum_get(op->ptr, "deform_axis"));
const eSculptMeshFilterType filter_type = eSculptMeshFilterType(RNA_enum_get(op->ptr, "type"));
const bool use_automasking = SCULPT_is_automasking_enabled(sd, ss, nullptr);
const bool needs_topology_info = sculpt_mesh_filter_needs_pmap(filter_type) || use_automasking;
if (deform_axis == 0) {
/* All axis are disabled, so the filter is not going to produce any deformation. */
@ -884,25 +768,21 @@ static int sculpt_mesh_filter_start(bContext *C, wmOperator *op)
/* Update the active face set manually as the paint cursor is not enabled when using the Mesh
* Filter Tool. */
float mval_fl[2] = {float(mval[0]), float(mval[1])};
float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
SculptCursorGeometryInfo sgi;
SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
}
SCULPT_vertex_random_access_ensure(ss);
BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_topology_info, false, false);
if (needs_topology_info) {
SCULPT_boundary_info_ensure(ob);
}
SCULPT_undo_push_begin(ob, op);
SCULPT_filter_cache_init(C,
ob,
sd,
SCULPT_UNDO_COORDS,
mval,
RNA_float_get(op->ptr, "area_normal_radius"),
RNA_float_get(op->ptr, "strength"));
SCULPT_filter_cache_init(
C, ob, sd, SCULPT_UNDO_COORDS, event->mval, RNA_float_get(op->ptr, "area_normal_radius"));
FilterCache *filter_cache = ss->filter_cache;
filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
@ -946,56 +826,12 @@ static int sculpt_mesh_filter_start(bContext *C, wmOperator *op)
RNA_enum_get(op->ptr, "orientation"));
ss->filter_cache->orientation = orientation;
return OPERATOR_PASS_THROUGH;
}
static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RNA_int_set_array(op->ptr, "start_mouse", event->mval);
int ret = sculpt_mesh_filter_start(C, op);
if (ret == OPERATOR_PASS_THROUGH) {
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
return ret;
}
static int sculpt_mesh_filter_exec(bContext *C, wmOperator *op)
{
int ret = sculpt_mesh_filter_start(C, op);
if (ret == OPERATOR_PASS_THROUGH) {
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
int iterations = RNA_int_get(op->ptr, "iteration_count");
bool has_history = RNA_collection_length(op->ptr, "event_history") > 0;
if (!has_history) {
ss->filter_cache->no_orig_co = true;
}
for (int i = 0; i < iterations; i++) {
sculpt_mesh_filter_apply_with_history(C, op);
ss->filter_cache->no_orig_co = true;
}
sculpt_mesh_filter_end(C, op);
return OPERATOR_FINISHED;
}
return ret;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
void SCULPT_mesh_filter_properties(wmOperatorType *ot)
{
RNA_def_int_array(
ot->srna, "start_mouse", 2, nullptr, 0, 1 << 14, "Starting Mouse", "", 0, 1 << 14);
RNA_def_float(
ot->srna,
"area_normal_radius",
@ -1008,31 +844,6 @@ void SCULPT_mesh_filter_properties(wmOperatorType *ot)
1.0);
RNA_def_float(
ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f);
RNA_def_int(ot->srna,
"iteration_count",
1,
1,
10000,
"Repeat",
"How many times to repeat the filter",
1,
100);
/* Smooth filter requires entire event history. */
PropertyRNA *prop = RNA_def_collection_runtime(
ot->srna, "event_history", &RNA_OperatorStrokeElement, "", "");
RNA_def_property_flag(prop, PropertyFlag(int(PROP_HIDDEN) | int(PROP_SKIP_SAVE)));
}
static void sculpt_mesh_ui_exec(bContext * /*C*/, wmOperator *op)
{
uiLayout *layout = op->layout;
uiItemR(layout, op->ptr, "strength", 0, nullptr, ICON_NONE);
uiItemR(layout, op->ptr, "iteration_count", 0, nullptr, ICON_NONE);
uiItemR(layout, op->ptr, "orientation", 0, nullptr, ICON_NONE);
layout = uiLayoutRow(layout, true);
uiItemR(layout, op->ptr, "deform_axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
void SCULPT_OT_mesh_filter(wmOperatorType *ot)
@ -1046,8 +857,6 @@ void SCULPT_OT_mesh_filter(wmOperatorType *ot)
ot->invoke = sculpt_mesh_filter_invoke;
ot->modal = sculpt_mesh_filter_modal;
ot->poll = SCULPT_mode_poll;
ot->exec = sculpt_mesh_filter_exec;
ot->ui = sculpt_mesh_ui_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;

View File

@ -494,8 +494,6 @@ struct FilterCache {
float (*pre_smoothed_color)[4];
ViewContext vc;
float start_filter_strength;
bool no_orig_co;
};
/**
@ -1429,8 +1427,7 @@ void SCULPT_filter_cache_init(bContext *C,
Sculpt *sd,
int undo_type,
const int mval[2],
float area_normal_radius,
float start_strength);
float area_normal_radius);
void SCULPT_filter_cache_free(SculptSession *ss);
void SCULPT_mesh_filter_properties(wmOperatorType *ot);

View File

@ -229,8 +229,6 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
SCULPT_topology_islands_invalidate(ss);
/* Redraw. */
SCULPT_pbvh_clear(ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);

View File

@ -58,7 +58,7 @@ void ED_sculpt_init_transform(bContext *C, Object *ob, const int mval[2], const
SCULPT_vertex_random_access_ensure(ss);
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS, mval, 5.0, 1.0f);
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS, mval, 5.0);
if (sd->transform_mode == SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC) {
ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL;

View File

@ -590,7 +590,7 @@ void ED_animedit_unlink_action(
if (nlt->strips.first == NULL) {
BLI_assert(nstrip == NULL);
BKE_nlatrack_remove_and_free(&adt->nla_tracks, nlt, true);
BKE_nlatrack_free(&adt->nla_tracks, nlt, true);
}
}
}

View File

@ -400,21 +400,6 @@ static void saction_channel_region_message_subscribe(const wmRegionMessageSubscr
}
}
static void action_clamp_scroll(ARegion *region)
{
View2D *v2d = &region->v2d;
const float cur_height_y = BLI_rctf_size_y(&v2d->cur);
if (BLI_rctf_size_y(&v2d->cur) > BLI_rctf_size_y(&v2d->tot)) {
v2d->cur.ymin = -cur_height_y;
v2d->cur.ymax = 0;
}
else if (v2d->cur.ymin < v2d->tot.ymin) {
v2d->cur.ymin = v2d->tot.ymin;
v2d->cur.ymax = v2d->cur.ymin + cur_height_y;
}
}
static void action_main_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
@ -875,13 +860,6 @@ static void action_blend_write(BlendWriter *writer, SpaceLink *sl)
BLO_write_struct(writer, SpaceAction, sl);
}
static void action_main_region_view2d_changed(const bContext *UNUSED(C), ARegion *region)
{
/* V2D_KEEPTOT_STRICT cannot be used to clamp scrolling
* because it also clamps the x-axis to 0. */
action_clamp_scroll(region);
}
void ED_spacetype_action(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype action");
@ -914,7 +892,6 @@ void ED_spacetype_action(void)
art->draw_overlay = action_main_region_draw_overlay;
art->listener = action_main_region_listener;
art->message_subscribe = saction_main_region_message_subscribe;
art->on_view2d_changed = action_main_region_view2d_changed;
art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);

View File

@ -128,55 +128,16 @@ static void draw_tile_background(const rcti *draw_rect, int colorid, int shade)
UI_draw_roundbox_aa(&draw_rect_fl, true, 5.0f, color);
}
static void file_but_enable_drag(uiBut *but,
const SpaceFile *sfile,
const FileDirEntry *file,
const char *path,
ImBuf *preview_image,
int icon,
float scale)
{
ID *id;
if ((id = filelist_file_get_id(file))) {
UI_but_drag_set_id(but, id);
if (preview_image) {
UI_but_drag_attach_image(but, preview_image, scale);
}
}
else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS &&
(file->typeflag & FILE_TYPE_ASSET) != 0) {
char blend_path[FILE_MAX_LIBEXTRA];
if (BLO_library_path_explode(path, blend_path, NULL, NULL)) {
const int import_method = ED_fileselect_asset_import_method_get(sfile, file);
BLI_assert(import_method > -1);
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
import_method,
icon,
preview_image,
scale);
}
}
else if (preview_image) {
UI_but_drag_set_image(but, BLI_strdup(path), icon, preview_image, scale, true);
}
else {
/* path is no more static, cannot give it directly to but... */
UI_but_drag_set_path(but, BLI_strdup(path), true);
}
}
static uiBut *file_add_icon_but(const SpaceFile *sfile,
uiBlock *block,
const char *path,
const rcti *tile_draw_rect,
int icon,
int width,
int height,
bool dimmed)
static void file_draw_icon(const SpaceFile *sfile,
uiBlock *block,
const FileDirEntry *file,
const char *path,
const rcti *tile_draw_rect,
int icon,
int width,
int height,
bool drag,
bool dimmed)
{
uiBut *but;
@ -190,7 +151,42 @@ static uiBut *file_add_icon_but(const SpaceFile *sfile,
block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, a1, a2, NULL);
UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path), MEM_freeN);
return but;
if (drag) {
/* TODO: duplicated from file_draw_preview(). */
ID *id;
if ((id = filelist_file_get_id(file))) {
UI_but_drag_set_id(but, id);
ImBuf *preview_image = filelist_file_getimage(file);
if (preview_image) {
UI_but_drag_attach_image(but, preview_image, UI_DPI_FAC);
}
}
else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS &&
(file->typeflag & FILE_TYPE_ASSET) != 0) {
ImBuf *preview_image = filelist_file_getimage(file);
char blend_path[FILE_MAX_LIBEXTRA];
if (BLO_library_path_explode(path, blend_path, NULL, NULL)) {
const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
BLI_assert(asset_params != NULL);
const int import_method = ED_fileselect_asset_import_method_get(sfile, file);
BLI_assert(import_method > -1);
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
import_method,
icon,
preview_image,
UI_DPI_FAC);
}
}
else {
/* path is no more static, cannot give it directly to but... */
UI_but_drag_set_path(but, BLI_strdup(path), true);
}
}
}
static void file_draw_string(int sx,
@ -301,50 +297,21 @@ void file_calc_previews(const bContext *C, ARegion *region)
UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height);
}
static void file_add_preview_drag_but(const SpaceFile *sfile,
uiBlock *block,
FileLayout *layout,
const FileDirEntry *file,
const char *path,
const rcti *tile_draw_rect,
ImBuf *preview_image,
const int icon,
const float scale)
{
/* Invisible button for dragging. */
rcti drag_rect = *tile_draw_rect;
/* A bit smaller than the full tile, to increase the gap between items that users can drag from
* for box select. */
BLI_rcti_pad(&drag_rect, -layout->tile_border_x, -layout->tile_border_y);
uiBut *but = uiDefBut(block,
UI_BTYPE_LABEL,
0,
"",
drag_rect.xmin,
drag_rect.ymin,
BLI_rcti_size_x(&drag_rect),
BLI_rcti_size_y(&drag_rect),
NULL,
0.0,
0.0,
0,
0,
NULL);
file_but_enable_drag(but, sfile, file, path, preview_image, icon, scale);
}
static void file_draw_preview(const FileDirEntry *file,
static void file_draw_preview(const SpaceFile *sfile,
uiBlock *block,
const FileDirEntry *file,
const char *path,
const rcti *tile_draw_rect,
const float icon_aspect,
ImBuf *imb,
const int icon,
FileLayout *layout,
const bool is_icon,
const bool drag,
const bool dimmed,
const bool is_link,
float *r_scale)
const bool is_link)
{
uiBut *but;
float fx, fy;
float dx, dy;
int xco, yco;
@ -561,11 +528,62 @@ static void file_draw_preview(const FileDirEntry *file,
immUnbindProgram();
}
GPU_blend(GPU_BLEND_NONE);
/* Invisible button for dragging. */
rcti drag_rect = *tile_draw_rect;
/* A bit smaller than the full tile, to increase the gap between items that users can drag from
* for box select. */
BLI_rcti_pad(&drag_rect, -layout->tile_border_x, -layout->tile_border_y);
if (r_scale) {
*r_scale = scale;
but = uiDefBut(block,
UI_BTYPE_LABEL,
0,
"",
drag_rect.xmin,
drag_rect.ymin,
BLI_rcti_size_x(&drag_rect),
BLI_rcti_size_y(&drag_rect),
NULL,
0.0,
0.0,
0,
0,
NULL);
/* Drag-region. */
if (drag) {
ID *id;
if ((id = filelist_file_get_id(file))) {
UI_but_drag_set_id(but, id);
UI_but_drag_attach_image(but, imb, scale);
}
/* path is no more static, cannot give it directly to but... */
else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS &&
(file->typeflag & FILE_TYPE_ASSET) != 0) {
char blend_path[FILE_MAX_LIBEXTRA];
if (BLO_library_path_explode(path, blend_path, NULL, NULL)) {
const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
BLI_assert(asset_params != NULL);
const int import_method = ED_fileselect_asset_import_method_get(sfile, file);
BLI_assert(import_method > -1);
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
import_method,
icon,
imb,
scale);
}
}
else {
UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true);
}
}
GPU_blend(GPU_BLEND_NONE);
}
static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
@ -1018,36 +1036,31 @@ void file_draw_list(const bContext *C, ARegion *region)
is_icon = 1;
}
float scale = 0;
file_draw_preview(file,
file_draw_preview(sfile,
block,
file,
path,
&tile_draw_rect,
thumb_icon_aspect,
imb,
icon,
layout,
is_icon,
do_drag,
is_hidden,
is_link,
/* Returns the scale which is needed below. */
&scale);
if (do_drag) {
file_add_preview_drag_but(
sfile, block, layout, file, path, &tile_draw_rect, imb, icon, scale);
}
is_link);
}
else {
const int icon = filelist_geticon(files, i, true);
uiBut *icon_but = file_add_icon_but(sfile,
block,
path,
&tile_draw_rect,
icon,
ICON_DEFAULT_WIDTH_SCALE,
ICON_DEFAULT_HEIGHT_SCALE,
is_hidden);
if (do_drag) {
file_but_enable_drag(icon_but, sfile, file, path, NULL, icon, UI_DPI_FAC);
}
file_draw_icon(sfile,
block,
file,
path,
&tile_draw_rect,
filelist_geticon(files, i, true),
ICON_DEFAULT_WIDTH_SCALE,
ICON_DEFAULT_HEIGHT_SCALE,
do_drag,
is_hidden);
icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
}

View File

@ -91,7 +91,7 @@ void get_graph_keyframe_extents(bAnimContext *ac,
/* Get range. */
if (BKE_fcurve_calc_bounds(
fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles, NULL)) {
fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
short mapping_flag = ANIM_get_normalization_flags(ac);
/* Apply NLA scaling. */

View File

@ -736,7 +736,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
}
/* call delete on this track - deletes all strips too */
BKE_nlatrack_remove_and_free(&adt->nla_tracks, nlt, true);
BKE_nlatrack_free(&adt->nla_tracks, nlt, true);
ale->update = ANIM_UPDATE_DEPS;
}
}

View File

@ -60,7 +60,7 @@ bool space_node_view_flag(
int tot = 0;
bool has_frame = false;
if (snode.edittree) {
for (const bNode *node : snode.edittree->all_nodes()) {
LISTBASE_FOREACH (const bNode *, node, &snode.edittree->nodes) {
if ((node->flag & node_flag) == node_flag) {
BLI_rctf_union(&cur_new, &node->runtime->totr);
tot++;

View File

@ -68,122 +68,6 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
return std::make_unique<ColumnValues>(column_id.name, GVArray::ForSpan(*values));
}
static void add_mesh_debug_column_names(
const Mesh &mesh,
const eAttrDomain domain,
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn)
{
switch (domain) {
case ATTR_DOMAIN_POINT:
if (CustomData_has_layer(&mesh.vdata, CD_ORIGINDEX)) {
fn({(char *)"Original Index"}, false);
}
break;
case ATTR_DOMAIN_EDGE:
if (CustomData_has_layer(&mesh.edata, CD_ORIGINDEX)) {
fn({(char *)"Original Index"}, false);
}
fn({(char *)"Vertex 1"}, false);
fn({(char *)"Vertex 2"}, false);
break;
case ATTR_DOMAIN_FACE:
if (CustomData_has_layer(&mesh.pdata, CD_ORIGINDEX)) {
fn({(char *)"Original Index"}, false);
}
fn({(char *)"Corner Start"}, false);
fn({(char *)"Corner Size"}, false);
break;
case ATTR_DOMAIN_CORNER:
fn({(char *)"Vertex"}, false);
fn({(char *)"Edge"}, false);
break;
default:
BLI_assert_unreachable();
break;
}
}
static std::unique_ptr<ColumnValues> build_mesh_debug_columns(const Mesh &mesh,
const eAttrDomain domain,
const StringRef name)
{
switch (domain) {
case ATTR_DOMAIN_POINT: {
if (name == "Original Index") {
const int *data = static_cast<const int *>(
CustomData_get_layer(&mesh.vdata, CD_ORIGINDEX));
if (data) {
return std::make_unique<ColumnValues>(name, VArray<int>::ForSpan({data, mesh.totvert}));
}
}
return {};
}
case ATTR_DOMAIN_EDGE: {
const Span<MEdge> edges = mesh.edges();
if (name == "Original Index") {
const int *data = static_cast<const int *>(
CustomData_get_layer(&mesh.edata, CD_ORIGINDEX));
if (data) {
return std::make_unique<ColumnValues>(name, VArray<int>::ForSpan({data, mesh.totedge}));
}
}
if (name == "Vertex 1") {
return std::make_unique<ColumnValues>(
name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
return edges[index].v1;
}));
}
if (name == "Vertex 2") {
return std::make_unique<ColumnValues>(
name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
return edges[index].v2;
}));
}
return {};
}
case ATTR_DOMAIN_FACE: {
const Span<MPoly> polys = mesh.polys();
if (name == "Original Index") {
const int *data = static_cast<const int *>(
CustomData_get_layer(&mesh.pdata, CD_ORIGINDEX));
if (data) {
return std::make_unique<ColumnValues>(name, VArray<int>::ForSpan({data, mesh.totpoly}));
}
}
if (name == "Corner Start") {
return std::make_unique<ColumnValues>(
name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
return polys[index].loopstart;
}));
}
if (name == "Corner Size") {
return std::make_unique<ColumnValues>(
name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
return polys[index].totloop;
}));
}
return {};
}
case ATTR_DOMAIN_CORNER: {
const Span<MLoop> loops = mesh.loops();
if (name == "Vertex") {
return std::make_unique<ColumnValues>(
name,
VArray<int>::ForFunc(loops.size(), [loops](int64_t index) { return loops[index].v; }));
}
if (name == "Edge") {
return std::make_unique<ColumnValues>(
name,
VArray<int>::ForFunc(loops.size(), [loops](int64_t index) { return loops[index].e; }));
}
return {};
}
default:
BLI_assert_unreachable();
return {};
}
}
void GeometryDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
@ -225,9 +109,17 @@ void GeometryDataSource::foreach_default_column_ids(
fn({(char *)"Scale"}, false);
}
else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
const MeshComponent &component = static_cast<const MeshComponent &>(*component_);
if (const Mesh *mesh = component.get_for_read()) {
add_mesh_debug_column_names(*mesh, domain_, fn);
if (domain_ == ATTR_DOMAIN_EDGE) {
fn({(char *)"Vertex 1"}, false);
fn({(char *)"Vertex 2"}, false);
}
else if (domain_ == ATTR_DOMAIN_FACE) {
fn({(char *)"Corner Start"}, false);
fn({(char *)"Corner Size"}, false);
}
else if (domain_ == ATTR_DOMAIN_CORNER) {
fn({(char *)"Vertex"}, false);
fn({(char *)"Edge"}, false);
}
}
}
@ -282,9 +174,51 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
const MeshComponent &component = static_cast<const MeshComponent &>(*component_);
if (const Mesh *mesh = component.get_for_read()) {
if (std::unique_ptr<ColumnValues> values = build_mesh_debug_columns(
*mesh, domain_, column_id.name)) {
return values;
const Span<MEdge> edges = mesh->edges();
const Span<MPoly> polys = mesh->polys();
const Span<MLoop> loops = mesh->loops();
if (domain_ == ATTR_DOMAIN_EDGE) {
if (STREQ(column_id.name, "Vertex 1")) {
return std::make_unique<ColumnValues>(
column_id.name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
return edges[index].v1;
}));
}
if (STREQ(column_id.name, "Vertex 2")) {
return std::make_unique<ColumnValues>(
column_id.name, VArray<int>::ForFunc(edges.size(), [edges](int64_t index) {
return edges[index].v2;
}));
}
}
else if (domain_ == ATTR_DOMAIN_FACE) {
if (STREQ(column_id.name, "Corner Start")) {
return std::make_unique<ColumnValues>(
column_id.name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
return polys[index].loopstart;
}));
}
if (STREQ(column_id.name, "Corner Size")) {
return std::make_unique<ColumnValues>(
column_id.name, VArray<int>::ForFunc(polys.size(), [polys](int64_t index) {
return polys[index].totloop;
}));
}
}
else if (domain_ == ATTR_DOMAIN_CORNER) {
if (STREQ(column_id.name, "Vertex")) {
return std::make_unique<ColumnValues>(
column_id.name, VArray<int>::ForFunc(loops.size(), [loops](int64_t index) {
return loops[index].v;
}));
}
if (STREQ(column_id.name, "Edge")) {
return std::make_unique<ColumnValues>(
column_id.name, VArray<int>::ForFunc(loops.size(), [loops](int64_t index) {
return loops[index].e;
}));
}
}
}
}

View File

@ -1499,7 +1499,7 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
const int totedge = mesh.totedge;
/* Reuse the same buffer as #vert_dest_map.
* NOTE: the caller must be made aware of it changes. */
* Note: the caller must be made aware of it changes. */
MutableSpan<int> vert_group_map = vert_dest_map;
WeldMesh weld_mesh;

View File

@ -839,6 +839,7 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
options.propagation_info,
attributes_to_propagate);
attributes_to_propagate.remove("position");
attributes_to_propagate.remove("normal");
attributes_to_propagate.remove("shade_smooth");
r_create_id = attributes_to_propagate.pop_try("id").has_value();
r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value();

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