Geometry Nodes: new Bake node #115466

Merged
Jacques Lucke merged 93 commits from JacquesLucke/blender:bake-geometry-nodes into main 2023-12-18 13:01:16 +01:00
459 changed files with 4624 additions and 4737 deletions
Showing only changes of commit e13e2b627b - Show all commits

View File

@ -53,15 +53,11 @@ endif()
# quiet output for Makefiles, 'make -s' helps too # quiet output for Makefiles, 'make -s' helps too
# set_property(GLOBAL PROPERTY RULE_MESSAGES OFF) # set_property(GLOBAL PROPERTY RULE_MESSAGES OFF)
# global compile definitions since add_definitions() adds for all. # Global compile definitions since add_definitions() adds for all.
# _DEBUG is a Visual Studio define, enabled for all platforms.
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
$<$<CONFIG:Debug>:DEBUG;_DEBUG> $<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG>
$<$<CONFIG:MinSizeRel>:NDEBUG>
$<$<CONFIG:RelWithDebInfo>:NDEBUG>
) )
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Set policy # Set policy
@ -99,7 +95,6 @@ endif()
include(build_files/cmake/macros.cmake) include(build_files/cmake/macros.cmake)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Initialize Project # Initialize Project
@ -733,6 +728,9 @@ mark_as_advanced(WITH_CXX_GUARDEDALLOC)
option(WITH_ASSERT_ABORT "Call abort() when raising an assertion through BLI_assert()" ON) option(WITH_ASSERT_ABORT "Call abort() when raising an assertion through BLI_assert()" ON)
mark_as_advanced(WITH_ASSERT_ABORT) mark_as_advanced(WITH_ASSERT_ABORT)
option(WITH_ASSERT_RELEASE "Build with asserts enabled even for non-debug configurations" OFF)
mark_as_advanced(WITH_ASSERT_RELEASE)
if((UNIX AND NOT APPLE) OR (CMAKE_GENERATOR MATCHES "^Visual Studio.+")) if((UNIX AND NOT APPLE) OR (CMAKE_GENERATOR MATCHES "^Visual Studio.+"))
option(WITH_CLANG_TIDY "\ option(WITH_CLANG_TIDY "\
Use Clang Tidy to analyze the source code \ Use Clang Tidy to analyze the source code \
@ -2165,6 +2163,20 @@ if(WITH_ASSERT_ABORT)
add_definitions(-DWITH_ASSERT_ABORT) add_definitions(-DWITH_ASSERT_ABORT)
endif() endif()
# NDEBUG is the standard C define to disable asserts.
if(WITH_ASSERT_RELEASE)
# CMake seemingly be setting the NDEBUG flag on its own already on some configurations
# therefore we need to remove the flags if they happen to be set.
remove_cc_flag("-DNDEBUG") # GCC/CLang
remove_cc_flag("/DNDEBUG") # MSVC
else()
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
$<$<CONFIG:Release>:NDEBUG>
$<$<CONFIG:MinSizeRel>:NDEBUG>
$<$<CONFIG:RelWithDebInfo>:NDEBUG>
)
endif()
# message(STATUS "Using CFLAGS: ${CMAKE_C_FLAGS}") # message(STATUS "Using CFLAGS: ${CMAKE_C_FLAGS}")
# message(STATUS "Using CXXFLAGS: ${CMAKE_CXX_FLAGS}") # message(STATUS "Using CXXFLAGS: ${CMAKE_CXX_FLAGS}")

View File

@ -9,6 +9,7 @@
# #
set(WITH_ASSERT_ABORT ON CACHE BOOL "" FORCE) set(WITH_ASSERT_ABORT ON CACHE BOOL "" FORCE)
set(WITH_ASSERT_RELEASE ON CACHE BOOL "" FORCE)
set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE) set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE)
# Sadly ASAN is more often broken than working with MSVC do not enable it in the # Sadly ASAN is more often broken than working with MSVC do not enable it in the
# developer profile for now. # developer profile for now.

View File

@ -1311,7 +1311,7 @@ int curve_fit_cubic_to_points_refit_db(
#ifdef USE_CORNER_DETECT #ifdef USE_CORNER_DETECT
if (use_corner) { if (use_corner) {
#ifdef DEBUG #ifndef NDEBUG
for (uint i = 0; i < knots_len; i++) { for (uint i = 0; i < knots_len; i++) {
assert(knots[i].heap_node == NULL); assert(knots[i].heap_node == NULL);
} }

View File

@ -206,7 +206,7 @@ static void rt_node_free(RangeTreeUInt *rt, Node *node);
#ifdef USE_BTREE #ifdef USE_BTREE
#ifdef DEBUG #ifndef NDEBUG
static bool rb_is_balanced_root(const Node *root); static bool rb_is_balanced_root(const Node *root);
#endif #endif
@ -238,7 +238,7 @@ static int key_cmp(uint key1, uint key2)
/* removed from the tree */ /* removed from the tree */
static void rb_node_invalidate(Node *node) static void rb_node_invalidate(Node *node)
{ {
#ifdef DEBUG #ifndef NDEBUG
node->left = NULL; node->left = NULL;
node->right = NULL; node->right = NULL;
node->color = false; node->color = false;
@ -481,7 +481,7 @@ static Node *rb_get_or_lower_recursive(Node *n, const uint key)
} }
} }
#ifdef DEBUG #ifndef NDEBUG
static bool rb_is_balanced_recursive(const Node *node, int black) static bool rb_is_balanced_recursive(const Node *node, int black)
{ {
@ -511,7 +511,7 @@ static bool rb_is_balanced_root(const Node *root)
return rb_is_balanced_recursive(root, black); return rb_is_balanced_recursive(root, black);
} }
#endif // DEBUG #endif // NDEBUG
/* End BTree API */ /* End BTree API */
@ -703,7 +703,7 @@ RangeTreeUInt *range_tree_uint_alloc(uint min, uint max)
void range_tree_uint_free(RangeTreeUInt *rt) void range_tree_uint_free(RangeTreeUInt *rt)
{ {
#ifdef DEBUG #ifndef NDEBUG
#ifdef USE_BTREE #ifdef USE_BTREE
assert(rb_is_balanced_root(rt->root)); assert(rb_is_balanced_root(rt->root));
#endif #endif

View File

@ -259,7 +259,7 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c
# else # else
options.append("Wno-parentheses-equality -Wno-unused-value --hipcc-func-supp -O3 -ffast-math"); options.append("Wno-parentheses-equality -Wno-unused-value --hipcc-func-supp -O3 -ffast-math");
# endif # endif
# ifdef _DEBUG # ifndef NDEBUG
options.append(" -save-temps"); options.append(" -save-temps");
# endif # endif
options.append(" --amdgpu-target=").append(arch); options.append(" --amdgpu-target=").append(arch);

View File

@ -4,6 +4,10 @@
#ifdef WITH_ONEAPI #ifdef WITH_ONEAPI
/* <algorithm> is needed until included upstream in sycl/detail/property_list_base.hpp */
# include <algorithm>
# include <sycl/sycl.hpp>
# include "device/oneapi/device_impl.h" # include "device/oneapi/device_impl.h"
# include "util/debug.h" # include "util/debug.h"
@ -25,6 +29,9 @@ extern "C" bool rtcIsSYCLDeviceSupported(const sycl::device sycl_device);
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
static std::vector<sycl::device> available_sycl_devices();
static int parse_driver_build_version(const sycl::device &device);
static void queue_error_cb(const char *message, void *user_ptr) static void queue_error_cb(const char *message, void *user_ptr)
{ {
if (user_ptr) { if (user_ptr) {
@ -545,7 +552,7 @@ void OneapiDevice::usm_free(void *usm_ptr)
void OneapiDevice::check_usm(SyclQueue *queue_, const void *usm_ptr, bool allow_host = false) void OneapiDevice::check_usm(SyclQueue *queue_, const void *usm_ptr, bool allow_host = false)
{ {
# ifdef _DEBUG # ifndef NDEBUG
sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_); sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
sycl::info::device_type device_type = sycl::info::device_type device_type =
queue->get_device().get_info<sycl::info::device::device_type>(); queue->get_device().get_info<sycl::info::device::device_type>();
@ -574,7 +581,7 @@ bool OneapiDevice::create_queue(SyclQueue *&external_queue,
{ {
bool finished_correct = true; bool finished_correct = true;
try { try {
std::vector<sycl::device> devices = OneapiDevice::available_devices(); std::vector<sycl::device> devices = available_sycl_devices();
if (device_index < 0 || device_index >= devices.size()) { if (device_index < 0 || device_index >= devices.size()) {
return false; return false;
} }
@ -862,7 +869,7 @@ static const int lowest_supported_driver_version_neo = 26957;
static const int lowest_supported_driver_version_neo = 26918; static const int lowest_supported_driver_version_neo = 26918;
# endif # endif
int OneapiDevice::parse_driver_build_version(const sycl::device &device) int parse_driver_build_version(const sycl::device &device)
{ {
const std::string &driver_version = device.get_info<sycl::info::device::driver_version>(); const std::string &driver_version = device.get_info<sycl::info::device::driver_version>();
int driver_build_version = 0; int driver_build_version = 0;
@ -901,7 +908,7 @@ int OneapiDevice::parse_driver_build_version(const sycl::device &device)
return driver_build_version; return driver_build_version;
} }
std::vector<sycl::device> OneapiDevice::available_devices() std::vector<sycl::device> available_sycl_devices()
{ {
bool allow_all_devices = false; bool allow_all_devices = false;
if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr) { if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr) {
@ -971,7 +978,7 @@ char *OneapiDevice::device_capabilities()
{ {
std::stringstream capabilities; std::stringstream capabilities;
const std::vector<sycl::device> &oneapi_devices = available_devices(); const std::vector<sycl::device> &oneapi_devices = available_sycl_devices();
for (const sycl::device &device : oneapi_devices) { for (const sycl::device &device : oneapi_devices) {
# ifndef WITH_ONEAPI_SYCL_HOST_TASK # ifndef WITH_ONEAPI_SYCL_HOST_TASK
const std::string &name = device.get_info<sycl::info::device::name>(); const std::string &name = device.get_info<sycl::info::device::name>();
@ -1080,7 +1087,7 @@ char *OneapiDevice::device_capabilities()
void OneapiDevice::iterate_devices(OneAPIDeviceIteratorCallback cb, void *user_ptr) void OneapiDevice::iterate_devices(OneAPIDeviceIteratorCallback cb, void *user_ptr)
{ {
int num = 0; int num = 0;
std::vector<sycl::device> devices = OneapiDevice::available_devices(); std::vector<sycl::device> devices = available_sycl_devices();
for (sycl::device &device : devices) { for (sycl::device &device : devices) {
const std::string &platform_name = const std::string &platform_name =
device.get_platform().get_info<sycl::info::platform::name>(); device.get_platform().get_info<sycl::info::platform::name>();

View File

@ -3,11 +3,6 @@
* SPDX-License-Identifier: Apache-2.0 */ * SPDX-License-Identifier: Apache-2.0 */
#ifdef WITH_ONEAPI #ifdef WITH_ONEAPI
/* <algorithm> is needed until included upstream in sycl/detail/property_list_base.hpp */
# include <algorithm>
# include <sycl/sycl.hpp>
# include "device/device.h" # include "device/device.h"
# include "device/oneapi/device.h" # include "device/oneapi/device.h"
# include "device/oneapi/queue.h" # include "device/oneapi/queue.h"
@ -106,9 +101,7 @@ class OneapiDevice : public Device {
void *usm_aligned_alloc_host(size_t memory_size, size_t alignment); void *usm_aligned_alloc_host(size_t memory_size, size_t alignment);
void usm_free(void *usm_ptr); void usm_free(void *usm_ptr);
static std::vector<sycl::device> available_devices();
static char *device_capabilities(); static char *device_capabilities();
static int parse_driver_build_version(const sycl::device &device);
static void iterate_devices(OneAPIDeviceIteratorCallback cb, void *user_ptr); static void iterate_devices(OneAPIDeviceIteratorCallback cb, void *user_ptr);
size_t get_memcapacity(); size_t get_memcapacity();

View File

@ -9,6 +9,7 @@
# include <array> # include <array>
# include "device/device.h" # include "device/device.h"
# include "device/oneapi/device_impl.h"
# include "device/queue.h" # include "device/queue.h"
# include "integrator/pass_accessor_cpu.h" # include "integrator/pass_accessor_cpu.h"
# include "session/buffers.h" # include "session/buffers.h"
@ -27,13 +28,10 @@
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
/* Ideally, this would be dynamic and adaptively change when the runtime runs out of memory. */ bool OIDNDenoiserGPU::is_device_supported(const DeviceInfo &device)
constexpr int prefilter_max_mem = 1024;
thread_mutex OIDNDenoiserGPU::mutex_;
bool OIDNDenoiserGPU::is_device_type_supported(const DeviceType &type)
{ {
switch (type) { /* Currently falls back to checking just the device type, can be improved. */
switch (device.type) {
# ifdef OIDN_DEVICE_SYCL # ifdef OIDN_DEVICE_SYCL
/* Assume all devices with Cycles support are also supported by OIDN2. */ /* Assume all devices with Cycles support are also supported by OIDN2. */
case DEVICE_ONEAPI: case DEVICE_ONEAPI:
@ -44,12 +42,6 @@ bool OIDNDenoiserGPU::is_device_type_supported(const DeviceType &type)
} }
} }
bool OIDNDenoiserGPU::is_device_supported(const DeviceInfo &device)
{
/* Currently falls back to checking just the device type, can be improved. */
return is_device_type_supported(device.type);
}
OIDNDenoiserGPU::OIDNDenoiserGPU(Device *path_trace_device, const DenoiseParams &params) OIDNDenoiserGPU::OIDNDenoiserGPU(Device *path_trace_device, const DenoiseParams &params)
: DenoiserGPU(path_trace_device, params) : DenoiserGPU(path_trace_device, params)
{ {
@ -123,9 +115,11 @@ bool OIDNDenoiserGPU::denoise_create_if_needed(DenoiseContext &context)
} }
switch (denoiser_device_->info.type) { switch (denoiser_device_->info.type) {
# if defined(OIDN_DEVICE_SYCL) # if defined(OIDN_DEVICE_SYCL) && defined(WITH_ONEAPI)
case DEVICE_ONEAPI: case DEVICE_ONEAPI:
oidn_device_ = oidnNewDevice(OIDN_DEVICE_TYPE_SYCL); oidn_device_ = oidnNewSYCLDevice(
(const sycl::queue *)reinterpret_cast<OneapiDevice *>(denoiser_device_)->sycl_queue(),
1);
denoiser_queue_->init_execution(); denoiser_queue_->init_execution();
break; break;
# endif # endif
@ -156,7 +150,6 @@ bool OIDNDenoiserGPU::denoise_create_if_needed(DenoiseContext &context)
if (context.use_pass_albedo) { if (context.use_pass_albedo) {
albedo_filter_ = create_filter(); albedo_filter_ = create_filter();
if (albedo_filter_ == nullptr) { if (albedo_filter_ == nullptr) {
oidnSetFilterInt(oidn_filter_, "maxMemoryMB", prefilter_max_mem);
return false; return false;
} }
} }
@ -164,7 +157,6 @@ bool OIDNDenoiserGPU::denoise_create_if_needed(DenoiseContext &context)
if (context.use_pass_normal) { if (context.use_pass_normal) {
normal_filter_ = create_filter(); normal_filter_ = create_filter();
if (normal_filter_ == nullptr) { if (normal_filter_ == nullptr) {
oidnSetFilterInt(oidn_filter_, "maxMemoryMB", prefilter_max_mem);
return false; return false;
} }
} }

View File

@ -34,15 +34,10 @@ class OIDNDenoiserGPU : public DenoiserGPU {
bool allow_inplace_modification) override; bool allow_inplace_modification) override;
static bool is_device_supported(const DeviceInfo &device); static bool is_device_supported(const DeviceInfo &device);
static bool is_device_type_supported(const DeviceType &type);
protected: protected:
virtual uint get_device_type_mask() const override; virtual uint get_device_type_mask() const override;
/* We only perform one denoising at a time, since OpenImageDenoise itself is multithreaded.
* Use this mutex whenever images are passed to the OIDN and needs to be denoised. */
static thread_mutex mutex_;
/* Create OIDN denoiser descriptor if needed. /* Create OIDN denoiser descriptor if needed.
* Will do nothing if the current OIDN descriptor is usable for the given parameters. * Will do nothing if the current OIDN descriptor is usable for the given parameters.
* If the OIDN denoiser descriptor did re-allocate here it is left unconfigured. */ * If the OIDN denoiser descriptor did re-allocate here it is left unconfigured. */

View File

@ -14,7 +14,8 @@
# pragma GCC diagnostic ignored "-Wlogical-op" # pragma GCC diagnostic ignored "-Wlogical-op"
#endif #endif
#ifdef __EIGEN3_MATRIX_C_API_CC__ /* quiet warning */ #ifdef __EIGEN3_MATRIX_C_API_CC__
/* Quiet warning. */
#endif #endif
#include <Eigen/Core> #include <Eigen/Core>

View File

@ -14,7 +14,8 @@
# pragma GCC diagnostic ignored "-Wlogical-op" # pragma GCC diagnostic ignored "-Wlogical-op"
#endif #endif
#ifdef __EIGEN3_SVD_C_API_CC__ /* quiet warning */ #ifdef __EIGEN3_SVD_C_API_CC__
/* Quiet warning. */
#endif #endif
#include <Eigen/Core> #include <Eigen/Core>

View File

@ -580,8 +580,8 @@ extern GHOST_ContextHandle GHOST_GetDrawingContext(GHOST_WindowHandle windowhand
extern void GHOST_SetTitle(GHOST_WindowHandle windowhandle, const char *title); extern void GHOST_SetTitle(GHOST_WindowHandle windowhandle, const char *title);
/** /**
* Returns the title displayed in the title bar. The title * Returns the title displayed in the title bar.
* should be free'd with free(). * The title must be freed with free().
* *
* \param windowhandle: The handle to the window. * \param windowhandle: The handle to the window.
* \return The title, free with free(). * \return The title, free with free().

View File

@ -316,7 +316,7 @@ typedef enum {
} GHOST_TEventType; } GHOST_TEventType;
typedef enum { typedef enum {
GHOST_kStandardCursorFirstCursor = 0, #define GHOST_kStandardCursorFirstCursor int(GHOST_kStandardCursorDefault)
GHOST_kStandardCursorDefault = 0, GHOST_kStandardCursorDefault = 0,
GHOST_kStandardCursorRightArrow, GHOST_kStandardCursorRightArrow,
GHOST_kStandardCursorLeftArrow, GHOST_kStandardCursorLeftArrow,
@ -357,7 +357,7 @@ typedef enum {
GHOST_kStandardCursorCopy, GHOST_kStandardCursorCopy,
GHOST_kStandardCursorCustom, GHOST_kStandardCursorCustom,
GHOST_kStandardCursorNumCursors #define GHOST_kStandardCursorNumCursors (int(GHOST_kStandardCursorCustom) + 1)
} GHOST_TStandardCursor; } GHOST_TStandardCursor;
typedef enum { typedef enum {

View File

@ -10,7 +10,7 @@
#pragma once #pragma once
#ifdef _MSC_VER #ifdef _MSC_VER
# ifdef DEBUG # ifdef _DEBUG
/* Suppress STL-MSVC debug info warning. */ /* Suppress STL-MSVC debug info warning. */
# pragma warning(disable : 4786) # pragma warning(disable : 4786)
# endif # endif

View File

@ -159,7 +159,7 @@ GHOST_TSuccess GHOST_DisplayManagerX11::setCurrentDisplaySetting(
fprintf(stderr, "Error: XF86VidMode extension missing!\n"); fprintf(stderr, "Error: XF86VidMode extension missing!\n");
return GHOST_kFailure; return GHOST_kFailure;
} }
# ifdef DEBUG # ifndef NDEBUG
printf("Using XFree86-VidModeExtension Version %d.%d\n", majorVersion, minorVersion); printf("Using XFree86-VidModeExtension Version %d.%d\n", majorVersion, minorVersion);
# endif # endif
@ -199,7 +199,7 @@ GHOST_TSuccess GHOST_DisplayManagerX11::setCurrentDisplaySetting(
} }
if (best_fit != -1) { if (best_fit != -1) {
# ifdef DEBUG # ifndef NDEBUG
printf("Switching to video mode %dx%d %dx%d %d\n", printf("Switching to video mode %dx%d %dx%d %d\n",
vidmodes[best_fit]->hdisplay, vidmodes[best_fit]->hdisplay,
vidmodes[best_fit]->vdisplay, vidmodes[best_fit]->vdisplay,

View File

@ -61,13 +61,6 @@ GHOST_TSuccess GHOST_System::putClipboardImage(uint * /*rgba*/,
return GHOST_kFailure; return GHOST_kFailure;
} }
uint64_t GHOST_System::getMilliSeconds() const
{
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
}
GHOST_ITimerTask *GHOST_System::installTimer(uint64_t delay, GHOST_ITimerTask *GHOST_System::installTimer(uint64_t delay,
uint64_t interval, uint64_t interval,
GHOST_TimerProcPtr timerProc, GHOST_TimerProcPtr timerProc,

View File

@ -54,14 +54,6 @@ class GHOST_System : public GHOST_ISystem {
* Time(r) functionality * Time(r) functionality
***************************************************************************************/ ***************************************************************************************/
/**
* Returns the system time.
* Returns the number of milliseconds since the start of the system process.
* Based on ANSI clock() routine.
* \return The number of milliseconds.
*/
virtual uint64_t getMilliSeconds() const;
/** /**
* Installs a timer. * Installs a timer.
* *

View File

@ -454,7 +454,8 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
switch (sdl_event->type) { switch (sdl_event->type) {
case SDL_WINDOWEVENT: { case SDL_WINDOWEVENT: {
SDL_WindowEvent &sdl_sub_evt = sdl_event->window; const SDL_WindowEvent &sdl_sub_evt = sdl_event->window;
const uint64_t event_ms = sdl_sub_evt.timestamp;
GHOST_WindowSDL *window = findGhostWindow( GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID)); SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
/* Can be nullptr on close window. */ /* Can be nullptr on close window. */
@ -464,22 +465,22 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
switch (sdl_sub_evt.event) { switch (sdl_sub_evt.event) {
case SDL_WINDOWEVENT_EXPOSED: case SDL_WINDOWEVENT_EXPOSED:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window); g_event = new GHOST_Event(event_ms, GHOST_kEventWindowUpdate, window);
break; break;
case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_RESIZED:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window); g_event = new GHOST_Event(event_ms, GHOST_kEventWindowSize, window);
break; break;
case SDL_WINDOWEVENT_MOVED: case SDL_WINDOWEVENT_MOVED:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, window); g_event = new GHOST_Event(event_ms, GHOST_kEventWindowMove, window);
break; break;
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window); g_event = new GHOST_Event(event_ms, GHOST_kEventWindowActivate, window);
break; break;
case SDL_WINDOWEVENT_FOCUS_LOST: case SDL_WINDOWEVENT_FOCUS_LOST:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window); g_event = new GHOST_Event(event_ms, GHOST_kEventWindowDeactivate, window);
break; break;
case SDL_WINDOWEVENT_CLOSE: case SDL_WINDOWEVENT_CLOSE:
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window); g_event = new GHOST_Event(event_ms, GHOST_kEventWindowClose, window);
break; break;
} }
@ -487,13 +488,16 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
} }
case SDL_QUIT: { case SDL_QUIT: {
const SDL_QuitEvent &sdl_sub_evt = sdl_event->quit;
const uint64_t event_ms = sdl_sub_evt.timestamp;
GHOST_IWindow *window = m_windowManager->getActiveWindow(); GHOST_IWindow *window = m_windowManager->getActiveWindow();
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventQuitRequest, window); g_event = new GHOST_Event(event_ms, GHOST_kEventQuitRequest, window);
break; break;
} }
case SDL_MOUSEMOTION: { case SDL_MOUSEMOTION: {
SDL_MouseMotionEvent &sdl_sub_evt = sdl_event->motion; const SDL_MouseMotionEvent &sdl_sub_evt = sdl_event->motion;
const uint64_t event_ms = sdl_sub_evt.timestamp;
SDL_Window *sdl_win = SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID); SDL_Window *sdl_win = SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID);
GHOST_WindowSDL *window = findGhostWindow(sdl_win); GHOST_WindowSDL *window = findGhostWindow(sdl_win);
assert(window != nullptr); assert(window != nullptr);
@ -535,7 +539,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win); SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win);
} }
g_event = new GHOST_EventCursor(getMilliSeconds(), g_event = new GHOST_EventCursor(event_ms,
GHOST_kEventCursorMove, GHOST_kEventCursorMove,
window, window,
x_new, x_new,
@ -543,7 +547,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
GHOST_TABLET_DATA_NONE); GHOST_TABLET_DATA_NONE);
} }
else { else {
g_event = new GHOST_EventCursor(getMilliSeconds(), g_event = new GHOST_EventCursor(event_ms,
GHOST_kEventCursorMove, GHOST_kEventCursorMove,
window, window,
x_root + x_accum, x_root + x_accum,
@ -554,18 +558,15 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
else else
#endif #endif
{ {
g_event = new GHOST_EventCursor(getMilliSeconds(), g_event = new GHOST_EventCursor(
GHOST_kEventCursorMove, event_ms, GHOST_kEventCursorMove, window, x_root, y_root, GHOST_TABLET_DATA_NONE);
window,
x_root,
y_root,
GHOST_TABLET_DATA_NONE);
} }
break; break;
} }
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN: { case SDL_MOUSEBUTTONDOWN: {
SDL_MouseButtonEvent &sdl_sub_evt = sdl_event->button; const SDL_MouseButtonEvent &sdl_sub_evt = sdl_event->button;
const uint64_t event_ms = sdl_sub_evt.timestamp;
GHOST_TButton gbmask = GHOST_kButtonMaskLeft; GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventButtonDown : GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventButtonDown :
GHOST_kEventButtonUp; GHOST_kEventButtonUp;
@ -595,21 +596,22 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
break; break;
} }
g_event = new GHOST_EventButton( g_event = new GHOST_EventButton(event_ms, type, window, gbmask, GHOST_TABLET_DATA_NONE);
getMilliSeconds(), type, window, gbmask, GHOST_TABLET_DATA_NONE);
break; break;
} }
case SDL_MOUSEWHEEL: { case SDL_MOUSEWHEEL: {
SDL_MouseWheelEvent &sdl_sub_evt = sdl_event->wheel; const SDL_MouseWheelEvent &sdl_sub_evt = sdl_event->wheel;
const uint64_t event_ms = sdl_sub_evt.timestamp;
GHOST_WindowSDL *window = findGhostWindow( GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID)); SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
assert(window != nullptr); assert(window != nullptr);
g_event = new GHOST_EventWheel(getMilliSeconds(), window, sdl_sub_evt.y); g_event = new GHOST_EventWheel(event_ms, window, sdl_sub_evt.y);
break; break;
} }
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: { case SDL_KEYUP: {
SDL_KeyboardEvent &sdl_sub_evt = sdl_event->key; const SDL_KeyboardEvent &sdl_sub_evt = sdl_event->key;
const uint64_t event_ms = sdl_sub_evt.timestamp;
GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventKeyDown : GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventKeyDown :
GHOST_kEventKeyUp; GHOST_kEventKeyUp;
const bool is_repeat = sdl_sub_evt.repeat != 0; const bool is_repeat = sdl_sub_evt.repeat != 0;
@ -629,7 +631,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
utf8_buf[0] = convert_keyboard_event_to_ascii(sdl_sub_evt); utf8_buf[0] = convert_keyboard_event_to_ascii(sdl_sub_evt);
} }
g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, is_repeat, utf8_buf); g_event = new GHOST_EventKey(event_ms, type, window, gkey, is_repeat, utf8_buf);
break; break;
} }
} }
@ -670,7 +672,9 @@ bool GHOST_SystemSDL::generateWindowExposeEvents()
bool anyProcessed = false; bool anyProcessed = false;
for (; w_start != w_end; ++w_start) { for (; w_start != w_end; ++w_start) {
GHOST_Event *g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, *w_start); /* The caller doesn't have a time-stamp. */
const uint64_t event_ms = getMilliSeconds();
GHOST_Event *g_event = new GHOST_Event(event_ms, GHOST_kEventWindowUpdate, *w_start);
(*w_start)->validate(); (*w_start)->validate();

View File

@ -394,7 +394,7 @@ struct GWL_Cursor {
wl_cursor_image image = {0}; wl_cursor_image image = {0};
wl_cursor_theme *theme = nullptr; wl_cursor_theme *theme = nullptr;
/** Only set when the cursor is from the theme (it may be animated). */ /** Only set when the cursor is from the theme (it may be animated). */
wl_cursor *theme_cursor = nullptr; const wl_cursor *theme_cursor = nullptr;
/** Needed so changing the theme scale can reload 'theme_cursor' at a new scale. */ /** Needed so changing the theme scale can reload 'theme_cursor' at a new scale. */
const char *theme_cursor_name = nullptr; const char *theme_cursor_name = nullptr;
} wl; } wl;
@ -1203,7 +1203,14 @@ struct GWL_RegistryEntry;
* see: #GHOST_SystemWayland::milliseconds_from_input_time. * see: #GHOST_SystemWayland::milliseconds_from_input_time.
*/ */
struct GWL_DisplayTimeStamp { struct GWL_DisplayTimeStamp {
uint64_t last = 0; /**
* When true, the GHOST & WAYLAND time-stamps are compatible,
* in most cases this means they will be equal however for systems with long up-times
* it may equal `uint32(GHOST_SystemWayland::getMilliSeconds())`,
* the `offsets` member is set to account for this case.
*/
bool exact_match = false;
uint32_t last = 0;
uint64_t offset = 0; uint64_t offset = 0;
}; };
@ -1936,47 +1943,64 @@ static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wp_ta
static const int default_cursor_size = 24; static const int default_cursor_size = 24;
static const std::unordered_map<GHOST_TStandardCursor, const char *> ghost_wl_cursors = { struct GWL_Cursor_ShapeInfo {
{GHOST_kStandardCursorDefault, "left_ptr"}, const char *names[GHOST_kStandardCursorNumCursors] = {0};
{GHOST_kStandardCursorRightArrow, "right_ptr"},
{GHOST_kStandardCursorLeftArrow, "left_ptr"},
{GHOST_kStandardCursorInfo, ""},
{GHOST_kStandardCursorDestroy, "pirate"},
{GHOST_kStandardCursorHelp, "question_arrow"},
{GHOST_kStandardCursorWait, "watch"},
{GHOST_kStandardCursorText, "xterm"},
{GHOST_kStandardCursorCrosshair, "crosshair"},
{GHOST_kStandardCursorCrosshairA, ""},
{GHOST_kStandardCursorCrosshairB, ""},
{GHOST_kStandardCursorCrosshairC, ""},
{GHOST_kStandardCursorPencil, "pencil"},
{GHOST_kStandardCursorUpArrow, "sb_up_arrow"},
{GHOST_kStandardCursorDownArrow, "sb_down_arrow"},
{GHOST_kStandardCursorVerticalSplit, "split_v"},
{GHOST_kStandardCursorHorizontalSplit, "split_h"},
{GHOST_kStandardCursorEraser, ""},
{GHOST_kStandardCursorKnife, ""},
{GHOST_kStandardCursorEyedropper, "color-picker"},
{GHOST_kStandardCursorZoomIn, "zoom-in"},
{GHOST_kStandardCursorZoomOut, "zoom-out"},
{GHOST_kStandardCursorMove, "move"},
{GHOST_kStandardCursorNSEWScroll, "size_all"}, /* Not an exact match. */
{GHOST_kStandardCursorNSScroll, "size_ver"}, /* Not an exact match. */
{GHOST_kStandardCursorEWScroll, "size_hor"}, /* Not an exact match. */
{GHOST_kStandardCursorStop, "not-allowed"},
{GHOST_kStandardCursorUpDown, "sb_v_double_arrow"},
{GHOST_kStandardCursorLeftRight, "sb_h_double_arrow"},
{GHOST_kStandardCursorTopSide, "top_side"},
{GHOST_kStandardCursorBottomSide, "bottom_side"},
{GHOST_kStandardCursorLeftSide, "left_side"},
{GHOST_kStandardCursorRightSide, "right_side"},
{GHOST_kStandardCursorTopLeftCorner, "top_left_corner"},
{GHOST_kStandardCursorTopRightCorner, "top_right_corner"},
{GHOST_kStandardCursorBottomRightCorner, "bottom_right_corner"},
{GHOST_kStandardCursorBottomLeftCorner, "bottom_left_corner"},
{GHOST_kStandardCursorCopy, "copy"},
}; };
static const GWL_Cursor_ShapeInfo ghost_wl_cursors = []() -> GWL_Cursor_ShapeInfo {
GWL_Cursor_ShapeInfo info{};
#define CASE_CURSOR(shape_id, shape_name_in_theme) \
case shape_id: \
info.names[int(shape_id)] = shape_name_in_theme;
/* Use a switch to ensure missing values show a compiler warning. */
switch (GHOST_kStandardCursorDefault) {
CASE_CURSOR(GHOST_kStandardCursorDefault, "left_ptr");
CASE_CURSOR(GHOST_kStandardCursorRightArrow, "right_ptr");
CASE_CURSOR(GHOST_kStandardCursorLeftArrow, "left_ptr");
CASE_CURSOR(GHOST_kStandardCursorInfo, "left_ptr_help");
CASE_CURSOR(GHOST_kStandardCursorDestroy, "pirate");
CASE_CURSOR(GHOST_kStandardCursorHelp, "question_arrow");
CASE_CURSOR(GHOST_kStandardCursorWait, "watch");
CASE_CURSOR(GHOST_kStandardCursorText, "xterm");
CASE_CURSOR(GHOST_kStandardCursorCrosshair, "crosshair");
CASE_CURSOR(GHOST_kStandardCursorCrosshairA, "");
CASE_CURSOR(GHOST_kStandardCursorCrosshairB, "");
CASE_CURSOR(GHOST_kStandardCursorCrosshairC, "");
CASE_CURSOR(GHOST_kStandardCursorPencil, "pencil");
CASE_CURSOR(GHOST_kStandardCursorUpArrow, "sb_up_arrow");
CASE_CURSOR(GHOST_kStandardCursorDownArrow, "sb_down_arrow");
CASE_CURSOR(GHOST_kStandardCursorVerticalSplit, "split_v");
CASE_CURSOR(GHOST_kStandardCursorHorizontalSplit, "split_h");
CASE_CURSOR(GHOST_kStandardCursorEraser, "");
CASE_CURSOR(GHOST_kStandardCursorKnife, "");
CASE_CURSOR(GHOST_kStandardCursorEyedropper, "color-picker");
CASE_CURSOR(GHOST_kStandardCursorZoomIn, "zoom-in");
CASE_CURSOR(GHOST_kStandardCursorZoomOut, "zoom-out");
CASE_CURSOR(GHOST_kStandardCursorMove, "move");
CASE_CURSOR(GHOST_kStandardCursorNSEWScroll, "all-scroll");
CASE_CURSOR(GHOST_kStandardCursorNSScroll, "size_ver");
CASE_CURSOR(GHOST_kStandardCursorEWScroll, "size_hor");
CASE_CURSOR(GHOST_kStandardCursorStop, "not-allowed");
CASE_CURSOR(GHOST_kStandardCursorUpDown, "sb_v_double_arrow");
CASE_CURSOR(GHOST_kStandardCursorLeftRight, "sb_h_double_arrow");
CASE_CURSOR(GHOST_kStandardCursorTopSide, "top_side");
CASE_CURSOR(GHOST_kStandardCursorBottomSide, "bottom_side");
CASE_CURSOR(GHOST_kStandardCursorLeftSide, "left_side");
CASE_CURSOR(GHOST_kStandardCursorRightSide, "right_side");
CASE_CURSOR(GHOST_kStandardCursorTopLeftCorner, "top_left_corner");
CASE_CURSOR(GHOST_kStandardCursorTopRightCorner, "top_right_corner");
CASE_CURSOR(GHOST_kStandardCursorBottomRightCorner, "bottom_right_corner");
CASE_CURSOR(GHOST_kStandardCursorBottomLeftCorner, "bottom_left_corner");
CASE_CURSOR(GHOST_kStandardCursorCopy, "copy");
CASE_CURSOR(GHOST_kStandardCursorCustom, "");
}
#undef CASE_CURSOR
return info;
}();
static constexpr const char *ghost_wl_mime_text_plain = "text/plain"; static constexpr const char *ghost_wl_mime_text_plain = "text/plain";
static constexpr const char *ghost_wl_mime_text_utf8 = "text/plain;charset=utf-8"; static constexpr const char *ghost_wl_mime_text_utf8 = "text/plain;charset=utf-8";
static constexpr const char *ghost_wl_mime_text_uri = "text/uri-list"; static constexpr const char *ghost_wl_mime_text_uri = "text/uri-list";
@ -6956,6 +6980,14 @@ uint8_t GHOST_SystemWayland::getNumDisplays() const
return display_ ? uint8_t(display_->outputs.size()) : 0; return display_ ? uint8_t(display_->outputs.size()) : 0;
} }
uint64_t GHOST_SystemWayland::getMilliSeconds() const
{
/* Match the timing method used by LIBINPUT, so the result is closer to WAYLAND's time-stamps. */
struct timespec ts = {0, 0};
clock_gettime(CLOCK_MONOTONIC, &ts);
return ((uint64_t(ts.tv_sec) * 1000) + (ts.tv_nsec / 1000000));
}
static GHOST_TSuccess getCursorPositionClientRelative_impl( static GHOST_TSuccess getCursorPositionClientRelative_impl(
const GWL_SeatStatePointer *seat_state_pointer, const GWL_SeatStatePointer *seat_state_pointer,
const GHOST_WindowWayland *win, const GHOST_WindowWayland *win,
@ -7530,7 +7562,7 @@ static void cursor_anim_begin(GWL_Seat *seat)
auto cursor_anim_frame_step_fn = auto cursor_anim_frame_step_fn =
[](GWL_Seat *seat, GWL_Cursor_AnimHandle *anim_handle, int delay) { [](GWL_Seat *seat, GWL_Cursor_AnimHandle *anim_handle, int delay) {
/* It's possible the `wl_cursor` is reloaded while the cursor is animating. /* It's possible the `wl_cursor` is reloaded while the cursor is animating.
* Don't access outside the lock, tha's why the `delay` is passed in. */ * Don't access outside the lock, that's why the `delay` is passed in. */
std::mutex *server_mutex = seat->system->server_mutex; std::mutex *server_mutex = seat->system->server_mutex;
int frame = 0; int frame = 0;
while (!anim_handle->exit_pending.load()) { while (!anim_handle->exit_pending.load()) {
@ -7538,7 +7570,7 @@ static void cursor_anim_begin(GWL_Seat *seat)
if (!anim_handle->exit_pending.load()) { if (!anim_handle->exit_pending.load()) {
std::lock_guard lock_server_guard{*server_mutex}; std::lock_guard lock_server_guard{*server_mutex};
if (!anim_handle->exit_pending.load()) { if (!anim_handle->exit_pending.load()) {
struct wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor; const struct wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
frame = (frame + 1) % wl_cursor->image_count; frame = (frame + 1) % wl_cursor->image_count;
wl_cursor_image *image = wl_cursor->images[frame]; wl_cursor_image *image = wl_cursor->images[frame];
wl_buffer *buffer = wl_cursor_image_get_buffer(image); wl_buffer *buffer = wl_cursor_image_get_buffer(image);
@ -7586,6 +7618,36 @@ static void cursor_anim_reset(GWL_Seat *seat)
cursor_anim_begin_if_needed(seat); cursor_anim_begin_if_needed(seat);
} }
static const wl_cursor *cursor_find_from_shape(GWL_Seat *seat,
const GHOST_TStandardCursor shape,
const char **r_cursor_name)
{
/* Caller must lock `server_mutex`. */
GWL_Cursor *cursor = &seat->cursor;
wl_cursor *wl_cursor = nullptr;
const char *cursor_name = ghost_wl_cursors.names[shape];
if (cursor_name[0] != '\0') {
if (!cursor->wl.theme) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
cursor->wl.theme = wl_cursor_theme_load(
cursor->theme_name.c_str(), cursor->theme_size, seat->system->wl_shm_get());
}
if (cursor->wl.theme) {
wl_cursor = wl_cursor_theme_get_cursor(cursor->wl.theme, cursor_name);
if (!wl_cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
}
}
}
if (r_cursor_name && wl_cursor) {
*r_cursor_name = cursor_name;
}
return wl_cursor;
}
GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor shape) GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor shape)
{ {
/* Caller must lock `server_mutex`. */ /* Caller must lock `server_mutex`. */
@ -7594,26 +7656,14 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor
if (UNLIKELY(!seat)) { if (UNLIKELY(!seat)) {
return GHOST_kFailure; return GHOST_kFailure;
} }
auto cursor_find = ghost_wl_cursors.find(shape);
const char *cursor_name = (cursor_find == ghost_wl_cursors.end()) ?
ghost_wl_cursors.at(GHOST_kStandardCursorDefault) :
(*cursor_find).second;
GWL_Cursor *cursor = &seat->cursor; const char *cursor_name = nullptr;
const wl_cursor *wl_cursor = cursor_find_from_shape(seat, shape, &cursor_name);
if (!cursor->wl.theme) { if (wl_cursor == nullptr) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
cursor->wl.theme = wl_cursor_theme_load(
cursor->theme_name.c_str(), cursor->theme_size, wl_shm_get());
}
wl_cursor *wl_cursor = wl_cursor_theme_get_cursor(cursor->wl.theme, cursor_name);
if (!wl_cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
return GHOST_kFailure; return GHOST_kFailure;
} }
GWL_Cursor *cursor = &seat->cursor;
wl_cursor_image *image = wl_cursor->images[0]; wl_cursor_image *image = wl_cursor->images[0];
wl_buffer *buffer = wl_cursor_image_get_buffer(image); wl_buffer *buffer = wl_cursor_image_get_buffer(image);
if (!buffer) { if (!buffer) {
@ -7635,12 +7685,9 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor
GHOST_TSuccess GHOST_SystemWayland::cursor_shape_check(const GHOST_TStandardCursor cursorShape) GHOST_TSuccess GHOST_SystemWayland::cursor_shape_check(const GHOST_TStandardCursor cursorShape)
{ {
/* No need to lock `server_mutex`. */ /* No need to lock `server_mutex`. */
auto cursor_find = ghost_wl_cursors.find(cursorShape); GWL_Seat *seat = gwl_display_seat_active_get(display_);
if (cursor_find == ghost_wl_cursors.end()) { const wl_cursor *wl_cursor = cursor_find_from_shape(seat, cursorShape, nullptr);
return GHOST_kFailure; if (wl_cursor == nullptr) {
}
const char *value = (*cursor_find).second;
if (*value == '\0') {
return GHOST_kFailure; return GHOST_kFailure;
} }
return GHOST_kSuccess; return GHOST_kSuccess;
@ -8147,15 +8194,28 @@ uint64_t GHOST_SystemWayland::ms_from_input_time(const uint32_t timestamp_as_uin
* This is updated because time may have passed between generating the time-stamp and `now`. * This is updated because time may have passed between generating the time-stamp and `now`.
* The method here is used by SDL. */ * The method here is used by SDL. */
const uint64_t now = getMilliSeconds();
GWL_DisplayTimeStamp &input_timestamp = display_->input_timestamp; GWL_DisplayTimeStamp &input_timestamp = display_->input_timestamp;
uint64_t timestamp = uint64_t(timestamp_as_uint); if (timestamp_as_uint < input_timestamp.last) {
if (timestamp < input_timestamp.last) {
/* 32-bit timer rollover, bump the offset. */ /* 32-bit timer rollover, bump the offset. */
input_timestamp.offset += uint64_t(std::numeric_limits<uint32_t>::max()) + 1; input_timestamp.offset += uint64_t(std::numeric_limits<uint32_t>::max()) + 1;
} }
input_timestamp.last = timestamp; input_timestamp.last = timestamp_as_uint;
uint64_t timestamp = uint64_t(timestamp_as_uint);
if (input_timestamp.exact_match) {
timestamp += input_timestamp.offset;
}
else {
const uint64_t now = getMilliSeconds();
const uint32_t now_as_uint32 = uint32_t(now);
if (now_as_uint32 == timestamp_as_uint) {
input_timestamp.exact_match = true;
/* For systems with up times exceeding 47 days
* it's possible we need to begin with an offset. */
input_timestamp.offset = now - uint64_t(now_as_uint32);
timestamp = now;
}
else {
if (!input_timestamp.offset) { if (!input_timestamp.offset) {
input_timestamp.offset = (now - timestamp); input_timestamp.offset = (now - timestamp);
} }
@ -8165,6 +8225,8 @@ uint64_t GHOST_SystemWayland::ms_from_input_time(const uint32_t timestamp_as_uin
input_timestamp.offset -= (timestamp - now); input_timestamp.offset -= (timestamp - now);
timestamp = now; timestamp = now;
} }
}
}
return timestamp; return timestamp;
} }

View File

@ -154,6 +154,8 @@ class GHOST_SystemWayland : public GHOST_System {
uint8_t getNumDisplays() const override; uint8_t getNumDisplays() const override;
uint64_t getMilliSeconds() const override;
GHOST_TSuccess getCursorPositionClientRelative(const GHOST_IWindow *window, GHOST_TSuccess getCursorPositionClientRelative(const GHOST_IWindow *window,
int32_t &x, int32_t &x,
int32_t &y) const override; int32_t &y) const override;

View File

@ -107,6 +107,7 @@ GHOST_SystemX11::GHOST_SystemX11()
: GHOST_System(), : GHOST_System(),
m_xkb_descr(nullptr), m_xkb_descr(nullptr),
m_start_time(0), m_start_time(0),
m_start_time_monotonic(0),
m_keyboard_vector{0}, m_keyboard_vector{0},
m_keycode_last_repeat_key(uint(-1)) m_keycode_last_repeat_key(uint(-1))
{ {
@ -172,14 +173,23 @@ GHOST_SystemX11::GHOST_SystemX11()
m_last_release_keycode = 0; m_last_release_keycode = 0;
m_last_release_time = 0; m_last_release_time = 0;
/* compute the initial time */ /* Compute the initial times. */
{
timeval tv; timeval tv;
if (gettimeofday(&tv, nullptr) == -1) { if (gettimeofday(&tv, nullptr) != 0) {
GHOST_ASSERT(false, "Could not instantiate timer!"); GHOST_ASSERT(false, "Could not instantiate timer!");
} }
/* Taking care not to overflow the `tv.tv_sec * 1000`. */ /* Taking care not to overflow the `tv.tv_sec * 1000`. */
m_start_time = uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000; m_start_time = uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
}
{
struct timespec ts = {0, 0};
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
GHOST_ASSERT(false, "Could not instantiate monotonic timer!");
}
m_start_time_monotonic = ((uint64_t(ts.tv_sec) * 1000) + (ts.tv_nsec / 1000000));
}
/* Use detectable auto-repeat, mac and windows also do this. */ /* Use detectable auto-repeat, mac and windows also do this. */
int use_xkb; int use_xkb;
@ -203,7 +213,7 @@ GHOST_SystemX11::GHOST_SystemX11()
#endif #endif
#ifdef WITH_X11_XINPUT #ifdef WITH_X11_XINPUT
/* detect if we have xinput (for reuse) */ /* Detect if we have XINPUT (for reuse). */
{ {
memset(&m_xinput_version, 0, sizeof(m_xinput_version)); memset(&m_xinput_version, 0, sizeof(m_xinput_version));
XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
@ -271,7 +281,7 @@ GHOST_TSuccess GHOST_SystemX11::init()
uint64_t GHOST_SystemX11::getMilliSeconds() const uint64_t GHOST_SystemX11::getMilliSeconds() const
{ {
timeval tv; timeval tv;
if (gettimeofday(&tv, nullptr) == -1) { if (gettimeofday(&tv, nullptr) != 0) {
GHOST_ASSERT(false, "Could not compute time!"); GHOST_ASSERT(false, "Could not compute time!");
} }
@ -279,6 +289,17 @@ uint64_t GHOST_SystemX11::getMilliSeconds() const
return uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000 - m_start_time; return uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000 - m_start_time;
} }
uint64_t GHOST_SystemX11::ms_from_input_time(const Time timestamp) const
{
GHOST_ASSERT(timestamp >= m_start_time_monotonic, "Invalid time-stemp");
/* NOTE(@ideasman42): Return a time compatible with `getMilliSeconds()`,
* this is needed as X11 time-stamps use monotonic time.
* The X11 implementation *could* use any basis, in practice though we are supporting
* XORG/LIBINPUT which uses time-stamps based on the monotonic time,
* Needed to resolve failure to detect double-clicking, see: #40009. */
return uint64_t(timestamp) - m_start_time_monotonic;
}
uint8_t GHOST_SystemX11::getNumDisplays() const uint8_t GHOST_SystemX11::getNumDisplays() const
{ {
return uint8_t(1); return uint8_t(1);
@ -637,6 +658,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
XPeekEvent(m_display, &xev_next); XPeekEvent(m_display, &xev_next);
if (ELEM(xev_next.type, KeyPress, KeyRelease)) { if (ELEM(xev_next.type, KeyPress, KeyRelease)) {
const uint64_t event_ms = ms_from_input_time(xev_next.xkey.time);
/* XK_Hyper_L/R currently unused. */ /* XK_Hyper_L/R currently unused. */
const static KeySym modifiers[] = { const static KeySym modifiers[] = {
XK_Shift_L, XK_Shift_L,
@ -652,7 +674,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
for (int i = 0; i < int(ARRAY_SIZE(modifiers)); i++) { for (int i = 0; i < int(ARRAY_SIZE(modifiers)); i++) {
KeyCode kc = XKeysymToKeycode(m_display, modifiers[i]); KeyCode kc = XKeysymToKeycode(m_display, modifiers[i]);
if (kc != 0 && ((xevent.xkeymap.key_vector[kc >> 3] >> (kc & 7)) & 1) != 0) { if (kc != 0 && ((xevent.xkeymap.key_vector[kc >> 3] >> (kc & 7)) & 1) != 0) {
pushEvent(new GHOST_EventKey(getMilliSeconds(), pushEvent(new GHOST_EventKey(event_ms,
GHOST_kEventKeyDown, GHOST_kEventKeyDown,
window, window,
ghost_key_from_keysym(modifiers[i]), ghost_key_from_keysym(modifiers[i]),
@ -850,16 +872,19 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
const XExposeEvent &xee = xe->xexpose; const XExposeEvent &xee = xe->xexpose;
if (xee.count == 0) { if (xee.count == 0) {
/* Only generate a single expose event /* Only generate a single expose event per read of the event queue. */
* per read of the event queue. */
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window); /* Event has no timestamp. */
const uint64_t event_ms = getMilliSeconds();
g_event = new GHOST_Event(event_ms, GHOST_kEventWindowUpdate, window);
} }
break; break;
} }
case MotionNotify: { case MotionNotify: {
const XMotionEvent &xme = xe->xmotion; const XMotionEvent &xme = xe->xmotion;
const uint64_t event_ms = ms_from_input_time(xme.time);
bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone; bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
@ -932,7 +957,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
setCursorPosition(x_new, y_new); /* wrap */ setCursorPosition(x_new, y_new); /* wrap */
} }
else { else {
g_event = new GHOST_EventCursor(getMilliSeconds(), g_event = new GHOST_EventCursor(event_ms,
GHOST_kEventCursorMove, GHOST_kEventCursorMove,
window, window,
xme.x_root + x_accum, xme.x_root + x_accum,
@ -941,7 +966,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
} }
} }
else { else {
g_event = new GHOST_EventCursor(getMilliSeconds(), g_event = new GHOST_EventCursor(event_ms,
GHOST_kEventCursorMove, GHOST_kEventCursorMove,
window, window,
xme.x_root, xme.x_root,
@ -954,6 +979,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case KeyPress: case KeyPress:
case KeyRelease: { case KeyRelease: {
XKeyEvent *xke = &(xe->xkey); XKeyEvent *xke = &(xe->xkey);
const uint64_t event_ms = ms_from_input_time(xke->time);
KeySym key_sym; KeySym key_sym;
char *utf8_buf = nullptr; char *utf8_buf = nullptr;
char ascii; char ascii;
@ -1146,7 +1172,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
} }
} }
g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, is_repeat, utf8_buf); g_event = new GHOST_EventKey(event_ms, type, window, gkey, is_repeat, utf8_buf);
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
/* when using IM for some languages such as Japanese, /* when using IM for some languages such as Japanese,
@ -1171,8 +1197,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* Enqueue previous character. */ /* Enqueue previous character. */
pushEvent(g_event); pushEvent(g_event);
g_event = new GHOST_EventKey( g_event = new GHOST_EventKey(event_ms, type, window, gkey, is_repeat, &utf8_buf[i]);
getMilliSeconds(), type, window, gkey, is_repeat, &utf8_buf[i]);
} }
} }
@ -1187,6 +1212,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case ButtonPress: case ButtonPress:
case ButtonRelease: { case ButtonRelease: {
const XButtonEvent &xbe = xe->xbutton; const XButtonEvent &xbe = xe->xbutton;
const uint64_t event_ms = ms_from_input_time(xbe.time);
GHOST_TButton gbmask = GHOST_kButtonMaskLeft; GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown : GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown :
GHOST_kEventButtonUp; GHOST_kEventButtonUp;
@ -1194,13 +1220,13 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* process wheel mouse events and break, only pass on press events */ /* process wheel mouse events and break, only pass on press events */
if (xbe.button == Button4) { if (xbe.button == Button4) {
if (xbe.type == ButtonPress) { if (xbe.type == ButtonPress) {
g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1); g_event = new GHOST_EventWheel(event_ms, window, 1);
} }
break; break;
} }
if (xbe.button == Button5) { if (xbe.button == Button5) {
if (xbe.type == ButtonPress) { if (xbe.type == ButtonPress) {
g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1); g_event = new GHOST_EventWheel(event_ms, window, -1);
} }
break; break;
} }
@ -1234,15 +1260,17 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
break; break;
} }
g_event = new GHOST_EventButton( g_event = new GHOST_EventButton(event_ms, type, window, gbmask, window->GetTabletData());
getMilliSeconds(), type, window, gbmask, window->GetTabletData());
break; break;
} }
/* change of size, border, layer etc. */ /* change of size, border, layer etc. */
case ConfigureNotify: { case ConfigureNotify: {
// const XConfigureEvent & xce = xe->xconfigure; // const XConfigureEvent & xce = xe->xconfigure;
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window); /* Event has no timestamp. */
const uint64_t event_ms = getMilliSeconds();
g_event = new GHOST_Event(event_ms, GHOST_kEventWindowSize, window);
break; break;
} }
@ -1338,8 +1366,9 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* also send grab/un-grab crossings for mouse-wheel events. * also send grab/un-grab crossings for mouse-wheel events.
*/ */
const XCrossingEvent &xce = xe->xcrossing; const XCrossingEvent &xce = xe->xcrossing;
const uint64_t event_ms = ms_from_input_time(xce.time);
if (xce.mode == NotifyNormal) { if (xce.mode == NotifyNormal) {
g_event = new GHOST_EventCursor(getMilliSeconds(), g_event = new GHOST_EventCursor(event_ms,
GHOST_kEventCursorMove, GHOST_kEventCursorMove,
window, window,
xce.x_root, xce.x_root,
@ -2538,8 +2567,12 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
void *data) void *data)
{ {
GHOST_SystemX11 *system = ((GHOST_SystemX11 *)getSystem()); GHOST_SystemX11 *system = ((GHOST_SystemX11 *)getSystem());
/* Caller has no timestamp. */
const uint64_t event_ms = system->getMilliSeconds();
return system->pushEvent(new GHOST_EventDragnDrop( return system->pushEvent(new GHOST_EventDragnDrop(
system->getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, data)); event_ms, eventType, draggedObjectType, window, mouseX, mouseY, data));
} }
#endif #endif
/** /**

View File

@ -200,6 +200,13 @@ class GHOST_SystemX11 : public GHOST_System {
} }
#endif #endif
/**
* Use this function instead of #GHOST_System::getMilliSeconds,
* passing in the time-stamp from X to input to get the event
* time-stamp with an offset applied to make it compatible with `getMilliSeconds`.
*/
uint64_t ms_from_input_time(const Time timestamp_as_uint) const;
/** Helped function for get data from the clipboard. */ /** Helped function for get data from the clipboard. */
void getClipboard_xcout(const XEvent *evt, void getClipboard_xcout(const XEvent *evt,
Atom sel, Atom sel,
@ -343,6 +350,8 @@ class GHOST_SystemX11 : public GHOST_System {
/** Start time at initialization. */ /** Start time at initialization. */
uint64_t m_start_time; uint64_t m_start_time;
/** Start time at initialization (using `CLOCK_MONOTONIC`). */
uint64_t m_start_time_monotonic;
/** A vector of keyboard key masks. */ /** A vector of keyboard key masks. */
char m_keyboard_vector[32]; char m_keyboard_vector[32];

View File

@ -1265,4 +1265,4 @@ void MEM_guarded_name_ptr_set(void *vmemh, const char *str)
MEMNEXT(memh->prev)->nextname = str; MEMNEXT(memh->prev)->nextname = str;
} }
} }
#endif /* NDEBUG */ #endif /* !NDEBUG */

View File

@ -440,4 +440,4 @@ const char *MEM_lockfree_name_ptr(void *vmemh)
} }
void MEM_lockfree_name_ptr_set(void *UNUSED(vmemh), const char *UNUSED(str)) {} void MEM_lockfree_name_ptr_set(void *UNUSED(vmemh), const char *UNUSED(str)) {}
#endif /* NDEBUG */ #endif /* !NDEBUG */

View File

@ -32,7 +32,7 @@ def extend(obj, EXTEND_MODE, use_uv_selection):
return STATUS_ERR_NOT_SELECTED # Active face is not selected. return STATUS_ERR_NOT_SELECTED # Active face is not selected.
if len(f_act.verts) != 4: if len(f_act.verts) != 4:
return STATUS_ERR_NOT_QUAD # Active face is not a quad return STATUS_ERR_NOT_QUAD # Active face is not a quad
if not me.uv_layers: if not bm.loops.layers.uv:
return STATUS_ERR_MISSING_UV_LAYER # Object's mesh doesn't have any UV layers. return STATUS_ERR_MISSING_UV_LAYER # Object's mesh doesn't have any UV layers.
uv_act = bm.loops.layers.uv.active # Always use the active UV layer. uv_act = bm.loops.layers.uv.active # Always use the active UV layer.
@ -240,6 +240,10 @@ def main(context, operator):
operator.report({'ERROR'}, "Active face must be a quad") operator.report({'ERROR'}, "Active face must be a quad")
elif status & STATUS_ERR_NOT_SELECTED: elif status & STATUS_ERR_NOT_SELECTED:
operator.report({'ERROR'}, "Active face not selected") operator.report({'ERROR'}, "Active face not selected")
elif status & STATUS_ERR_NO_FACES_SELECTED:
operator.report({'ERROR'}, "No selected faces")
elif status & STATUS_ERR_MISSING_UV_LAYER:
operator.report({'ERROR'}, "No UV layers")
else: else:
assert status & STATUS_ERR_ACTIVE_FACE != 0 assert status & STATUS_ERR_ACTIVE_FACE != 0
operator.report({'ERROR'}, "No active face") operator.report({'ERROR'}, "No active face")

View File

@ -281,12 +281,13 @@ class GREASE_PENCIL_MT_layer_active(Menu):
layout = self.layout layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN' layout.operator_context = 'INVOKE_REGION_WIN'
obd = context.active_object.data obd = context.active_object.data
if not obd.layers:
return
nlop = layout.operator("grease_pencil.layer_add", text="New Layer", icon='ADD') nlop = layout.operator("grease_pencil.layer_add", text="New Layer", icon='ADD')
nlop.new_layer_name = "Layer" nlop.new_layer_name = "Layer"
if not obd.layers:
return
layout.separator() layout.separator()
for i in range(len(obd.layers) - 1, -1, -1): for i in range(len(obd.layers) - 1, -1, -1):

View File

@ -1042,6 +1042,8 @@ class VIEW3D_HT_header(Header):
sub.popover(panel="VIEW3D_PT_overlay_vertex_paint", text="", icon='VPAINT_HLT') sub.popover(panel="VIEW3D_PT_overlay_vertex_paint", text="", icon='VPAINT_HLT')
elif obj is not None and obj.type == 'GPENCIL': elif obj is not None and obj.type == 'GPENCIL':
sub.popover(panel="VIEW3D_PT_overlay_gpencil_options", text="", icon='OUTLINER_DATA_GREASEPENCIL') sub.popover(panel="VIEW3D_PT_overlay_gpencil_options", text="", icon='OUTLINER_DATA_GREASEPENCIL')
elif obj is not None and obj.type == 'GREASEPENCIL':
sub.popover(panel="VIEW3D_PT_overlay_grease_pencil_options", text="", icon='OUTLINER_DATA_GREASEPENCIL')
# Separate from `elif` chain because it may coexist with weight-paint. # Separate from `elif` chain because it may coexist with weight-paint.
if ( if (
@ -3565,7 +3567,7 @@ class VIEW3D_MT_sculpt(Menu):
props.action = 'SHOW' props.action = 'SHOW'
props.area = 'ALL' props.area = 'ALL'
layout.operator("sculpt.face_set_invert_visibility", text="Invert Visible") layout.operator("paint.visibility_invert", text="Invert Visible")
props = layout.operator("paint.hide_show", text="Hide Masked") props = layout.operator("paint.hide_show", text="Hide Masked")
props.action = 'HIDE' props.action = 'HIDE'
@ -3786,14 +3788,6 @@ class VIEW3D_MT_face_sets(Menu):
layout.separator() layout.separator()
layout.operator("sculpt.face_set_invert_visibility", text="Invert Visible Face Sets")
props = layout.operator("paint.hide_show", text="Show All Face Sets")
props.action = "SHOW"
props.area = "ALL"
layout.separator()
props = layout.operator("sculpt.face_sets_randomize_colors", text="Randomize Colors") props = layout.operator("sculpt.face_sets_randomize_colors", text="Randomize Colors")
layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label) layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label)
@ -6142,7 +6136,7 @@ class VIEW3D_MT_sculpt_face_sets_edit_pie(Menu):
props = pie.operator("sculpt.face_sets_create", text="Face Set from Visible") props = pie.operator("sculpt.face_sets_create", text="Face Set from Visible")
props.mode = 'VISIBLE' props.mode = 'VISIBLE'
pie.operator("sculpt.face_set_invert_visibility", text="Invert Visible") pie.operator("paint.visibility_invert", text="Invert Visible")
props = pie.operator("paint.hide_show", text="Show All") props = pie.operator("paint.hide_show", text="Show All")
props.action = "SHOW" props.action = "SHOW"
@ -7796,6 +7790,33 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
row.prop(overlay, "gpencil_vertex_paint_opacity", text="Opacity", slider=True) row.prop(overlay, "gpencil_vertex_paint_opacity", text="Opacity", slider=True)
class VIEW3D_PT_overlay_grease_pencil_options(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = ""
bl_ui_units_x = 13
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'GREASEPENCIL'
def draw(self, context):
layout = self.layout
view = context.space_data
overlay = view.overlay
layout.label(text={
'PAINT_GREASE_PENCIL': iface_("Draw Grease Pencil"),
'EDIT_GREASE_PENCIL': iface_("Edit Grease Pencil"),
'OBJECT': iface_("Grease Pencil"),
}[context.mode], translate=False)
if context.object.mode in {'EDIT'}:
split = layout.split()
col = split.column()
col.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines")
class VIEW3D_PT_quad_view(Panel): class VIEW3D_PT_quad_view(Panel):
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
@ -8961,6 +8982,7 @@ classes = (
VIEW3D_PT_gpencil_guide, VIEW3D_PT_gpencil_guide,
VIEW3D_PT_transform_orientations, VIEW3D_PT_transform_orientations,
VIEW3D_PT_overlay_gpencil_options, VIEW3D_PT_overlay_gpencil_options,
VIEW3D_PT_overlay_grease_pencil_options,
VIEW3D_PT_context_properties, VIEW3D_PT_context_properties,
VIEW3D_PT_paint_vertex_context_menu, VIEW3D_PT_paint_vertex_context_menu,
VIEW3D_PT_paint_texture_context_menu, VIEW3D_PT_paint_texture_context_menu,

View File

@ -61,7 +61,9 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
* \param flag: Optional flags (#eInsertKeyFlags) for controlling how keys get added * \param flag: Optional flags (#eInsertKeyFlags) for controlling how keys get added
* and/or whether updates get done. * and/or whether updates get done.
*/ */
int insert_vert_fcurve( int insert_vert_fcurve(FCurve *fcu,
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag); const float2 position,
eBezTriple_KeyframeType keyframe_type,
eInsertKeyFlags flag);
} // namespace blender::animrig } // namespace blender::animrig

View File

@ -137,7 +137,7 @@ static void bonecoll_ensure_name_unique(bArmature *armature, BoneCollection *bco
} }
/** /**
* Inserts bcoll into armature's array of bone collecions at index. * Inserts bcoll into armature's array of bone collections at index.
* *
* Note: the specified index is where the given bone collection will end up. * Note: the specified index is where the given bone collection will end up.
* This means, for example, that for a collection array of length N, you can * This means, for example, that for a collection array of length N, you can

View File

@ -260,11 +260,13 @@ void initialize_bezt(BezTriple *beztr,
beztr->period = 4.1f; beztr->period = 4.1f;
} }
int insert_vert_fcurve( int insert_vert_fcurve(FCurve *fcu,
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag) const float2 position,
eBezTriple_KeyframeType keyframe_type,
eInsertKeyFlags flag)
{ {
BezTriple beztr = {{{0}}}; BezTriple beztr = {{{0}}};
initialize_bezt(&beztr, {x, y}, keyframe_type, flag, eFCurve_Flags(fcu->flag)); initialize_bezt(&beztr, position, keyframe_type, flag, eFCurve_Flags(fcu->flag));
uint oldTot = fcu->totvert; uint oldTot = fcu->totvert;
int a; int a;

View File

@ -315,14 +315,14 @@ static bool insert_keyframe_value(
return false; return false;
} }
if (insert_vert_fcurve(fcu, cfra, curval, keytype, flag) < 0) { if (insert_vert_fcurve(fcu, {cfra, curval}, keytype, flag) < 0) {
return false; return false;
} }
return true; return true;
} }
return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0; return insert_vert_fcurve(fcu, {cfra, curval}, keytype, flag) >= 0;
} }
bool insert_keyframe_direct(ReportList *reports, bool insert_keyframe_direct(ReportList *reports,

View File

@ -345,7 +345,7 @@ int BLF_load_default(bool unique);
int BLF_load_mono_default(bool unique); int BLF_load_mono_default(bool unique);
void BLF_load_font_stack(void); void BLF_load_font_stack(void);
#ifdef DEBUG #ifndef NDEBUG
void BLF_state_print(int fontid); void BLF_state_print(int fontid);
#endif #endif

View File

@ -1017,7 +1017,7 @@ float BLF_character_to_curves(int fontid,
return blf_character_to_curves(font, unicode, nurbsbase, scale); return blf_character_to_curves(font, unicode, nurbsbase, scale);
} }
#ifdef DEBUG #ifndef NDEBUG
void BLF_state_print(int fontid) void BLF_state_print(int fontid)
{ {
FontBLF *font = blf_get(fontid); FontBLF *font = blf_get(fontid);

View File

@ -765,7 +765,7 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode
} }
} }
#ifdef DEBUG #ifndef NDEBUG
printf("Unicode character U+%04X not found in loaded fonts. \n", charcode); printf("Unicode character U+%04X not found in loaded fonts. \n", charcode);
#endif #endif

View File

@ -349,7 +349,7 @@ typedef struct FontBLF {
int char_weight; /* 100 - 900, 400 = normal. */ int char_weight; /* 100 - 900, 400 = normal. */
float char_slant; /* Slant in clockwise degrees. 0.0 = upright. */ float char_slant; /* Slant in clockwise degrees. 0.0 = upright. */
float char_width; /* Factor of normal character width. 1.0 = normal. */ float char_width; /* Factor of normal character width. 1.0 = normal. */
float char_spacing; /* Factor of normal normal spacing. 0.0 = normal. */ float char_spacing; /* Factor of normal character spacing. 0.0 = normal. */
/** Max texture size. */ /** Max texture size. */
int tex_size_max; int tex_size_max;

View File

@ -43,7 +43,7 @@ using eCustomDataMask = uint64_t;
/** /**
* UV map related customdata offsets into BMesh attribute blocks. See #BM_uv_map_get_offsets. * UV map related customdata offsets into BMesh attribute blocks. See #BM_uv_map_get_offsets.
* Defined in #BKE_customdata.hh to avoid including bmesh.h in many unrelated areas. * Defined in #BKE_customdata.hh to avoid including bmesh.hh in many unrelated areas.
* An offset of -1 means that the corresponding layer does not exist. * An offset of -1 means that the corresponding layer does not exist.
*/ */
struct BMUVOffsets { struct BMUVOffsets {
@ -347,6 +347,11 @@ void CustomData_bmesh_copy_data(const CustomData *source,
CustomData *dest, CustomData *dest,
void *src_block, void *src_block,
void **dest_block); void **dest_block);
/**
* Copy all layers from the source to the destination block.
* Allocate the result block if necessary, otherwise free its existing layer data.
*/
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block);
void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source, void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
CustomData *dest, CustomData *dest,
void *src_block, void *src_block,
@ -509,11 +514,6 @@ const char *CustomData_get_render_layer_name(const CustomData *data, eCustomData
bool CustomData_layer_is_anonymous(const CustomData *data, eCustomDataType type, int n); bool CustomData_layer_is_anonymous(const CustomData *data, eCustomDataType type, int n);
void CustomData_bmesh_set(const CustomData *data,
void *block,
eCustomDataType type,
const void *source);
void CustomData_bmesh_set_n( void CustomData_bmesh_set_n(
CustomData *data, void *block, eCustomDataType type, int n, const void *source); CustomData *data, void *block, eCustomDataType type, int n, const void *source);
@ -757,7 +757,7 @@ size_t CustomData_get_elem_size(const CustomDataLayer *layer);
struct DynStr; struct DynStr;
/** Use to inspect mesh data when debugging. */ /** Use to inspect mesh data when debugging. */
void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr); void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr);
#endif /* NDEBUG */ #endif /* !NDEBUG */
namespace blender::bke { namespace blender::bke {
const CPPType *custom_data_type_to_cpp_type(eCustomDataType type); const CPPType *custom_data_type_to_cpp_type(eCustomDataType type);

View File

@ -13,7 +13,7 @@
*/ */
#include "DNA_customdata_types.h" #include "DNA_customdata_types.h"
#include "bmesh.h" #include "bmesh.hh"
struct BMLoop; struct BMLoop;
struct BMPartialUpdate; struct BMPartialUpdate;

View File

@ -473,16 +473,6 @@ void BKE_mesh_merge_customdata_for_apply_modifier(struct Mesh *me);
/* Flush flags. */ /* Flush flags. */
/**
* Update the hide flag for edges and faces from the corresponding flag in verts.
*/
void BKE_mesh_flush_hidden_from_verts(struct Mesh *me);
void BKE_mesh_flush_hidden_from_faces(struct Mesh *me);
void BKE_mesh_flush_select_from_faces(struct Mesh *me);
void BKE_mesh_flush_select_from_verts(struct Mesh *me);
void BKE_mesh_flush_select_from_edges(struct Mesh *me);
/* spatial evaluation */ /* spatial evaluation */
/** /**
* This function takes the difference between 2 vertex-coord-arrays * This function takes the difference between 2 vertex-coord-arrays

View File

@ -297,6 +297,18 @@ void mesh_vert_normals_assign(Mesh &mesh, Span<float3> vert_normals);
/** Set mesh vertex normals to known-correct values, avoiding future lazy computation. */ /** Set mesh vertex normals to known-correct values, avoiding future lazy computation. */
void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals); void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals);
/** Make edge and face visibility consistent with vertices. */
void mesh_hide_vert_flush(Mesh &mesh);
/** Make vertex and edge visibility consistent with faces. */
void mesh_hide_face_flush(Mesh &mesh);
/** Make edge and face visibility consistent with vertices. */
void mesh_select_vert_flush(Mesh &mesh);
/** Make vertex and face visibility consistent with edges. */
void mesh_select_edge_flush(Mesh &mesh);
/** Make vertex and edge visibility consistent with faces. */
void mesh_select_face_flush(Mesh &mesh);
} // namespace blender::bke } // namespace blender::bke
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */

View File

@ -81,4 +81,4 @@ void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
#ifndef NDEBUG #ifndef NDEBUG
bool BKE_mesh_runtime_is_valid(Mesh *me_eval); bool BKE_mesh_runtime_is_valid(Mesh *me_eval);
#endif /* NDEBUG */ #endif /* !NDEBUG */

View File

@ -140,7 +140,7 @@ struct MeshRuntime {
CustomData_MeshMasks cd_mask_extra = {}; CustomData_MeshMasks cd_mask_extra = {};
/** /**
* Grids representation for multiresolution sculpting. When this is set, the mesh will be empty, * Grids representation for multi-resolution sculpting. When this is set, the mesh will be empty,
* since it is conceptually replaced with the limited data stored in the grids. * since it is conceptually replaced with the limited data stored in the grids.
*/ */
std::unique_ptr<SubdivCCG> subdiv_ccg; std::unique_ptr<SubdivCCG> subdiv_ccg;

View File

@ -100,7 +100,7 @@ class NodeDeclaration;
class NodeDeclarationBuilder; class NodeDeclarationBuilder;
class GatherAddNodeSearchParams; class GatherAddNodeSearchParams;
class GatherLinkSearchOpParams; class GatherLinkSearchOpParams;
class NodeExtraInfoParams; struct NodeExtraInfoParams;
} // namespace nodes } // namespace nodes
namespace realtime_compositor { namespace realtime_compositor {
class Context; class Context;

View File

@ -25,7 +25,7 @@
#include "BKE_attribute.h" #include "BKE_attribute.h"
#include "BKE_pbvh.hh" #include "BKE_pbvh.hh"
#include "bmesh.h" #include "bmesh.hh"
struct BMFace; struct BMFace;
struct BMesh; struct BMesh;
@ -196,7 +196,6 @@ const Brush *BKE_paint_brush_for_read(const Paint *p);
void BKE_paint_brush_set(Paint *paint, Brush *br); void BKE_paint_brush_set(Paint *paint, Brush *br);
Palette *BKE_paint_palette(Paint *paint); Palette *BKE_paint_palette(Paint *paint);
void BKE_paint_palette_set(Paint *p, Palette *palette); void BKE_paint_palette_set(Paint *p, Palette *palette);
void BKE_paint_curve_set(Brush *br, PaintCurve *pc);
void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, int add_index); void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, int add_index);
/** /**
@ -607,12 +606,12 @@ struct SculptSession {
* geometry (the trim tool, for example) to detect which geometry was just added, so it can be * geometry (the trim tool, for example) to detect which geometry was just added, so it can be
* assigned a valid Face Set after creation. Tools are not intended to run with Face Sets IDs set * assigned a valid Face Set after creation. Tools are not intended to run with Face Sets IDs set
* to 0. */ * to 0. */
int *face_sets; const int *face_sets;
/** /**
* A reference to the ".hide_poly" attribute, to store whether (base) faces are hidden. * A reference to the ".hide_poly" attribute, to store whether (base) faces are hidden.
* May be null. * May be null.
*/ */
bool *hide_poly; const bool *hide_poly;
/* BMesh for dynamic topology sculpting */ /* BMesh for dynamic topology sculpting */
BMesh *bm; BMesh *bm;
@ -775,11 +774,6 @@ SculptAttribute *BKE_sculpt_attribute_get(Object *ob,
eCustomDataType proptype, eCustomDataType proptype,
const char *name); const char *name);
bool BKE_sculpt_attribute_exists(Object *ob,
eAttrDomain domain,
eCustomDataType proptype,
const char *name);
bool BKE_sculpt_attribute_destroy(Object *ob, SculptAttribute *attr); bool BKE_sculpt_attribute_destroy(Object *ob, SculptAttribute *attr);
/* Destroy all attributes and pseudo-attributes created by sculpt mode. */ /* Destroy all attributes and pseudo-attributes created by sculpt mode. */
@ -848,13 +842,11 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval);
* it's the last modifier on the stack and it is not on the first level. * it's the last modifier on the stack and it is not on the first level.
*/ */
MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob); MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob);
int *BKE_sculpt_face_sets_ensure(Object *ob);
/** /**
* Create the attribute used to store face visibility and retrieve its data. * Update the pointer to the ".hide_poly" attribute. This is necessary because it is dynamically
* Note that changes to the face visibility have to be propagated to other domains * created, removed, and made mutable.
* (see #SCULPT_visibility_sync_all_from_faces).
*/ */
bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh); void BKE_sculpt_hide_poly_pointer_update(Object &object);
/** /**
* Ensures a mask layer exists. If depsgraph and bmain are non-null, * Ensures a mask layer exists. If depsgraph and bmain are non-null,
@ -874,7 +866,6 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob);
void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg); void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg);
void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object);
void BKE_sculpt_sync_face_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg); void BKE_sculpt_sync_face_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg);
/** /**

View File

@ -29,7 +29,7 @@
#include "BKE_ccg.h" #include "BKE_ccg.h"
#include "BKE_pbvh.hh" #include "BKE_pbvh.hh"
#include "bmesh.h" #include "bmesh.hh"
struct BMLog; struct BMLog;
struct BMesh; struct BMesh;
@ -384,6 +384,10 @@ int BKE_pbvh_node_num_unique_verts(const PBVH &pbvh, const PBVHNode &node);
blender::Span<int> BKE_pbvh_node_get_vert_indices(const PBVHNode *node); blender::Span<int> BKE_pbvh_node_get_vert_indices(const PBVHNode *node);
blender::Span<int> BKE_pbvh_node_get_unique_vert_indices(const PBVHNode *node); blender::Span<int> BKE_pbvh_node_get_unique_vert_indices(const PBVHNode *node);
void BKE_pbvh_node_get_loops(const PBVHNode *node, const int **r_loop_indices); void BKE_pbvh_node_get_loops(const PBVHNode *node, const int **r_loop_indices);
void BKE_pbvh_node_calc_face_indices(const PBVH &pbvh,
const PBVHNode &node,
blender::Vector<int> &faces);
blender::Vector<int> BKE_pbvh_node_calc_face_indices(const PBVH &pbvh, const PBVHNode &node); blender::Vector<int> BKE_pbvh_node_calc_face_indices(const PBVH &pbvh, const PBVHNode &node);
/* Get number of faces in the mesh; for PBVH_GRIDS the /* Get number of faces in the mesh; for PBVH_GRIDS the

View File

@ -92,7 +92,7 @@ std::optional<int> BKE_previewimg_deferred_thumb_source_get(const PreviewImage *
/** /**
* Create an #ImBuf holding a copy of the preview image buffer in \a prv. * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
* \note The returned image buffer has to be free'd (#IMB_freeImBuf()). * \note The returned image buffer has to be freed (#IMB_freeImBuf()).
*/ */
ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, int size); ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, int size);

View File

@ -84,7 +84,7 @@ static bool is_appdir_init = false;
# define ASSERT_IS_INIT() BLI_assert(is_appdir_init) # define ASSERT_IS_INIT() BLI_assert(is_appdir_init)
#else #else
# define ASSERT_IS_INIT() ((void)0) # define ASSERT_IS_INIT() ((void)0)
#endif #endif /* NDEBUG */
void BKE_appdir_init() void BKE_appdir_init()
{ {
@ -882,7 +882,7 @@ static void where_am_i(char *program_filepath,
/* Remove "/./" and "/../" so string comparisons can be used on the path. */ /* Remove "/./" and "/../" so string comparisons can be used on the path. */
BLI_path_normalize_native(program_filepath); BLI_path_normalize_native(program_filepath);
# if defined(DEBUG) # ifndef NDEBUG
if (!STREQ(program_name, program_filepath)) { if (!STREQ(program_name, program_filepath)) {
CLOG_INFO(&LOG, 2, "guessing '%s' == '%s'", program_name, program_filepath); CLOG_INFO(&LOG, 2, "guessing '%s' == '%s'", program_name, program_filepath);
} }

View File

@ -807,20 +807,6 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
return nullptr; return nullptr;
} }
/**
* Get list of domain types but with ATTR_DOMAIN_FACE and
* ATTR_DOMAIN_CORNER swapped.
*/
static void get_domains_types(eAttrDomain domains[ATTR_DOMAIN_NUM])
{
for (const int i : IndexRange(ATTR_DOMAIN_NUM)) {
domains[i] = static_cast<eAttrDomain>(i);
}
/* Swap corner and face. */
std::swap(domains[ATTR_DOMAIN_FACE], domains[ATTR_DOMAIN_CORNER]);
}
int BKE_id_attribute_to_index(const ID *id, int BKE_id_attribute_to_index(const ID *id,
const CustomDataLayer *layer, const CustomDataLayer *layer,
eAttrDomainMask domain_mask, eAttrDomainMask domain_mask,
@ -831,21 +817,19 @@ int BKE_id_attribute_to_index(const ID *id,
} }
DomainInfo info[ATTR_DOMAIN_NUM]; DomainInfo info[ATTR_DOMAIN_NUM];
eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info); get_domains(id, info);
int index = 0; int index = 0;
for (int i = 0; i < ATTR_DOMAIN_NUM; i++) { for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
if (!(domain_mask & (1 << domains[i])) || !info[domains[i]].customdata) { const CustomData *customdata = info[domain].customdata;
if (!customdata || !((1 << int(domain)) & domain_mask)) {
continue; continue;
} }
const CustomData *cdata = info[domains[i]].customdata; for (int i = 0; i < customdata->totlayer; i++) {
for (int j = 0; j < cdata->totlayer; j++) { const CustomDataLayer *layer_iter = customdata->layers + i;
const CustomDataLayer *layer_iter = cdata->layers + j; if (!(layer_mask & CD_TYPE_AS_MASK(layer_iter->type)) ||
if (!(CD_TYPE_AS_MASK(layer_iter->type) & layer_mask) ||
(layer_iter->flag & CD_FLAG_TEMPORARY)) { (layer_iter->flag & CD_FLAG_TEMPORARY)) {
continue; continue;
} }

View File

@ -681,7 +681,7 @@ void MutableAttributeAccessor::remove_anonymous()
/** /**
* Debug utility that checks whether the #finish function of an #AttributeWriter has been called. * Debug utility that checks whether the #finish function of an #AttributeWriter has been called.
*/ */
#ifdef DEBUG #ifndef NDEBUG
struct FinishCallChecker { struct FinishCallChecker {
std::string name; std::string name;
bool finish_called = false; bool finish_called = false;
@ -700,7 +700,7 @@ GAttributeWriter MutableAttributeAccessor::lookup_for_write(const AttributeIDRef
{ {
GAttributeWriter attribute = fn_->lookup_for_write(owner_, attribute_id); GAttributeWriter attribute = fn_->lookup_for_write(owner_, attribute_id);
/* Check that the #finish method is called in debug builds. */ /* Check that the #finish method is called in debug builds. */
#ifdef DEBUG #ifndef NDEBUG
if (attribute) { if (attribute) {
auto checker = std::make_shared<FinishCallChecker>(); auto checker = std::make_shared<FinishCallChecker>();
checker->name = attribute_id.name(); checker->name = attribute_id.name();

View File

@ -323,7 +323,8 @@ static void userdef_free_addons(UserDef *userdef)
void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts) void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
{ {
#define U BLI_STATIC_ASSERT(false, "Global 'U' not allowed, only use arguments passed in!") #define U BLI_STATIC_ASSERT(false, "Global 'U' not allowed, only use arguments passed in!")
#ifdef U /* quiet warning */ #ifdef U
/* Quiet warning. */
#endif #endif
userdef_free_keymaps(userdef); userdef_free_keymaps(userdef);

View File

@ -1217,7 +1217,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(BVHTreeFromMesh *data,
bvhcache_insert(*bvh_cache_p, data->tree, bvh_cache_type); bvhcache_insert(*bvh_cache_p, data->tree, bvh_cache_type);
bvhcache_unlock(*bvh_cache_p, lock_started); bvhcache_unlock(*bvh_cache_p, lock_started);
#ifdef DEBUG #ifndef NDEBUG
if (data->tree != nullptr) { if (data->tree != nullptr) {
if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) { if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) {
printf("tree_type %d obtained instead of %d\n", printf("tree_type %d obtained instead of %d\n",
@ -1307,7 +1307,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
bvhcache_unlock(*bvh_cache_p, lock_started); bvhcache_unlock(*bvh_cache_p, lock_started);
} }
#ifdef DEBUG #ifndef NDEBUG
if (data->tree != nullptr) { if (data->tree != nullptr) {
if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) { if (BLI_bvhtree_get_tree_type(data->tree) != tree_type) {
printf("tree_type %d obtained instead of %d\n", printf("tree_type %d obtained instead of %d\n",

View File

@ -72,7 +72,7 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num)
MEM_malloc_arrayN(this->curve_num + 1, sizeof(int), __func__)); MEM_malloc_arrayN(this->curve_num + 1, sizeof(int), __func__));
this->runtime->curve_offsets_sharing_info = implicit_sharing::info_for_mem_free( this->runtime->curve_offsets_sharing_info = implicit_sharing::info_for_mem_free(
this->curve_offsets); this->curve_offsets);
#ifdef DEBUG #ifndef NDEBUG
this->offsets_for_write().fill(-1); this->offsets_for_write().fill(-1);
#endif #endif
/* Set common values for convenience. */ /* Set common values for convenience. */

View File

@ -54,7 +54,7 @@
#include "BLO_read_write.hh" #include "BLO_read_write.hh"
#include "bmesh.h" #include "bmesh.hh"
#include "CLG_log.h" #include "CLG_log.h"
@ -65,6 +65,7 @@ using blender::BitVector;
using blender::float2; using blender::float2;
using blender::ImplicitSharingInfo; using blender::ImplicitSharingInfo;
using blender::IndexRange; using blender::IndexRange;
using blender::MutableSpan;
using blender::Set; using blender::Set;
using blender::Span; using blender::Span;
using blender::StringRef; using blender::StringRef;
@ -138,7 +139,7 @@ struct LayerTypeInfo {
* size should be the size of one element of this layer's data (e.g. * size should be the size of one element of this layer's data (e.g.
* LayerTypeInfo.size) * LayerTypeInfo.size)
*/ */
void (*free)(void *data, int count, int size); void (*free)(void *data, int count);
/** /**
* a function to interpolate between count source elements of this * a function to interpolate between count source elements of this
@ -224,15 +225,13 @@ static void layerCopy_mdeformvert(const void *source, void *dest, const int coun
} }
} }
static void layerFree_mdeformvert(void *data, const int count, const int size) static void layerFree_mdeformvert(void *data, const int count)
{ {
for (int i = 0; i < count; i++) { for (MDeformVert &dvert : MutableSpan(static_cast<MDeformVert *>(data), count)) {
MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(data, i * size)); if (dvert.dw) {
MEM_freeN(dvert.dw);
if (dvert->dw) { dvert.dw = nullptr;
MEM_freeN(dvert->dw); dvert.totweight = 0;
dvert->dw = nullptr;
dvert->totweight = 0;
} }
} }
} }
@ -666,21 +665,13 @@ static void layerCopy_mdisps(const void *source, void *dest, const int count)
} }
} }
static void layerFree_mdisps(void *data, const int count, const int /*size*/) static void layerFree_mdisps(void *data, const int count)
{ {
MDisps *d = static_cast<MDisps *>(data); for (MDisps &d : MutableSpan(static_cast<MDisps *>(data), count)) {
MEM_SAFE_FREE(d.disps);
for (int i = 0; i < count; i++) { MEM_SAFE_FREE(d.hidden);
if (d[i].disps) { d.totdisp = 0;
MEM_freeN(d[i].disps); d.level = 0;
}
if (d[i].hidden) {
MEM_freeN(d[i].hidden);
}
d[i].disps = nullptr;
d[i].hidden = nullptr;
d[i].totdisp = 0;
d[i].level = 0;
} }
} }
@ -757,10 +748,10 @@ void bpy_bm_generic_invalidate(struct BPy_BMGeneric * /*self*/)
} }
#endif #endif
static void layerFree_bmesh_elem_py_ptr(void *data, const int count, const int size) static void layerFree_bmesh_elem_py_ptr(void *data, const int count)
{ {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
void **ptr = (void **)POINTER_OFFSET(data, i * size); void **ptr = (void **)POINTER_OFFSET(data, i * sizeof(void *));
if (*ptr) { if (*ptr) {
bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr)); bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr));
} }
@ -790,13 +781,11 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, const int
} }
} }
static void layerFree_grid_paint_mask(void *data, const int count, const int /*size*/) static void layerFree_grid_paint_mask(void *data, const int count)
{ {
GridPaintMask *gpm = static_cast<GridPaintMask *>(data); for (GridPaintMask &gpm : MutableSpan(static_cast<GridPaintMask *>(data), count)) {
MEM_SAFE_FREE(gpm.data);
for (int i = 0; i < count; i++) { gpm.level = 0;
MEM_SAFE_FREE(gpm[i].data);
gpm[i].level = 0;
} }
} }
@ -2155,7 +2144,7 @@ static void free_layer_data(const eCustomDataType type, const void *data, const
{ {
const LayerTypeInfo &type_info = *layerType_getInfo(type); const LayerTypeInfo &type_info = *layerType_getInfo(type);
if (type_info.free) { if (type_info.free) {
type_info.free(const_cast<void *>(data), totelem, type_info.size); type_info.free(const_cast<void *>(data), totelem);
} }
MEM_freeN(const_cast<void *>(data)); MEM_freeN(const_cast<void *>(data));
} }
@ -3364,7 +3353,7 @@ void CustomData_free_elem(CustomData *data, const int index, const int count)
size_t offset = size_t(index) * typeInfo->size; size_t offset = size_t(index) * typeInfo->size;
BLI_assert(layer_is_mutable(data->layers[i])); BLI_assert(layer_is_mutable(data->layers[i]));
typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size); typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count);
} }
} }
} }
@ -3756,7 +3745,7 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
if (typeInfo->free) { if (typeInfo->free) {
int offset = data->layers[i].offset; int offset = data->layers[i].offset;
typeInfo->free(POINTER_OFFSET(*block, offset), 1, typeInfo->size); typeInfo->free(POINTER_OFFSET(*block, offset), 1);
} }
} }
@ -3776,7 +3765,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type));
if (typeInfo->free) { if (typeInfo->free) {
const size_t offset = data->layers[i].offset; const size_t offset = data->layers[i].offset;
typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); typeInfo->free(POINTER_OFFSET(block, offset), 1);
} }
} }
if (data->totsize) { if (data->totsize) {
@ -3810,7 +3799,7 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type));
const size_t offset = data->layers[i].offset; const size_t offset = data->layers[i].offset;
if (typeInfo->free) { if (typeInfo->free) {
typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size); typeInfo->free(POINTER_OFFSET(block, offset), 1);
} }
memset(POINTER_OFFSET(block, offset), 0, typeInfo->size); memset(POINTER_OFFSET(block, offset), 0, typeInfo->size);
} }
@ -3910,6 +3899,35 @@ void CustomData_bmesh_copy_data(const CustomData *source,
CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0); CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0);
} }
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block)
{
if (*dst_block) {
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
const LayerTypeInfo &info = *layerType_getInfo(eCustomDataType(layer.type));
if (info.free) {
info.free(POINTER_OFFSET(*dst_block, layer.offset), 1);
}
}
}
else {
if (data.totsize == 0) {
return;
}
*dst_block = BLI_mempool_alloc(data.pool);
}
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
const int offset = layer.offset;
const LayerTypeInfo &info = *layerType_getInfo(eCustomDataType(layer.type));
if (info.copy) {
info.copy(POINTER_OFFSET(src_block, offset), POINTER_OFFSET(*dst_block, offset), 1);
}
else {
memcpy(POINTER_OFFSET(*dst_block, offset), POINTER_OFFSET(src_block, offset), info.size);
}
}
}
void *CustomData_bmesh_get(const CustomData *data, void *block, const eCustomDataType type) void *CustomData_bmesh_get(const CustomData *data, void *block, const eCustomDataType type)
{ {
int layer_index = CustomData_get_active_layer_index(data, type); int layer_index = CustomData_get_active_layer_index(data, type);
@ -4085,26 +4103,6 @@ void CustomData_data_add(const eCustomDataType type, void *data1, const void *da
} }
} }
void CustomData_bmesh_set(const CustomData *data,
void *block,
const eCustomDataType type,
const void *source)
{
void *dest = CustomData_bmesh_get(data, block, type);
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
if (!dest) {
return;
}
if (typeInfo->copy) {
typeInfo->copy(source, dest, 1);
}
else {
memcpy(dest, source, typeInfo->size);
}
}
void CustomData_bmesh_set_n( void CustomData_bmesh_set_n(
CustomData *data, void *block, const eCustomDataType type, const int n, const void *source) CustomData *data, void *block, const eCustomDataType type, const int n, const void *source)
{ {
@ -4498,7 +4496,7 @@ void CustomData_external_reload(CustomData *data, ID * /*id*/, eCustomDataMask m
} }
else if ((layer->flag & CD_FLAG_EXTERNAL) && (layer->flag & CD_FLAG_IN_MEMORY)) { else if ((layer->flag & CD_FLAG_EXTERNAL) && (layer->flag & CD_FLAG_IN_MEMORY)) {
if (typeInfo->free) { if (typeInfo->free) {
typeInfo->free(layer->data, totelem, typeInfo->size); typeInfo->free(layer->data, totelem);
} }
layer->flag &= ~CD_FLAG_IN_MEMORY; layer->flag &= ~CD_FLAG_IN_MEMORY;
} }
@ -4673,7 +4671,7 @@ void CustomData_external_write(
if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
if (free) { if (free) {
if (typeInfo->free) { if (typeInfo->free) {
typeInfo->free(layer->data, totelem, typeInfo->size); typeInfo->free(layer->data, totelem);
} }
layer->flag &= ~CD_FLAG_IN_MEMORY; layer->flag &= ~CD_FLAG_IN_MEMORY;
} }
@ -5275,7 +5273,7 @@ void CustomData_debug_info_from_layers(const CustomData *data, const char *inden
} }
} }
#endif /* NDEBUG */ #endif /* !NDEBUG */
/** \} */ /** \} */

View File

@ -32,9 +32,9 @@ TEST(evaluate_fcurve, OnKeys)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {1.0f, 7.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {2.0f, 13.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 3.0f, 19.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {3.0f, 19.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
EXPECT_NEAR(evaluate_fcurve(fcu, 1.0f), 7.0f, EPSILON); /* hits 'on or before first' function */ EXPECT_NEAR(evaluate_fcurve(fcu, 1.0f), 7.0f, EPSILON); /* hits 'on or before first' function */
EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f), 13.0f, EPSILON); /* hits 'between' function */ EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f), 13.0f, EPSILON); /* hits 'between' function */
@ -55,8 +55,10 @@ TEST(evaluate_fcurve, InterpolationConstant)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); EXPECT_EQ(insert_vert_fcurve(fcu, {1.0f, 7.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); 0);
EXPECT_EQ(insert_vert_fcurve(fcu, {2.0f, 13.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
1);
fcu->bezt[0].ipo = BEZT_IPO_CONST; fcu->bezt[0].ipo = BEZT_IPO_CONST;
fcu->bezt[1].ipo = BEZT_IPO_CONST; fcu->bezt[1].ipo = BEZT_IPO_CONST;
@ -71,8 +73,10 @@ TEST(evaluate_fcurve, InterpolationLinear)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); EXPECT_EQ(insert_vert_fcurve(fcu, {1.0f, 7.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); 0);
EXPECT_EQ(insert_vert_fcurve(fcu, {2.0f, 13.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
1);
fcu->bezt[0].ipo = BEZT_IPO_LIN; fcu->bezt[0].ipo = BEZT_IPO_LIN;
fcu->bezt[1].ipo = BEZT_IPO_LIN; fcu->bezt[1].ipo = BEZT_IPO_LIN;
@ -88,8 +92,10 @@ TEST(evaluate_fcurve, InterpolationBezier)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); EXPECT_EQ(insert_vert_fcurve(fcu, {1.0f, 7.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); 0);
EXPECT_EQ(insert_vert_fcurve(fcu, {2.0f, 13.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
1);
EXPECT_EQ(fcu->bezt[0].ipo, BEZT_IPO_BEZ); EXPECT_EQ(fcu->bezt[0].ipo, BEZT_IPO_BEZ);
EXPECT_EQ(fcu->bezt[1].ipo, BEZT_IPO_BEZ); EXPECT_EQ(fcu->bezt[1].ipo, BEZT_IPO_BEZ);
@ -121,8 +127,10 @@ TEST(evaluate_fcurve, InterpolationBounce)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); EXPECT_EQ(insert_vert_fcurve(fcu, {1.0f, 7.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); 0);
EXPECT_EQ(insert_vert_fcurve(fcu, {2.0f, 13.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
1);
fcu->bezt[0].ipo = BEZT_IPO_BOUNCE; fcu->bezt[0].ipo = BEZT_IPO_BOUNCE;
fcu->bezt[1].ipo = BEZT_IPO_BOUNCE; fcu->bezt[1].ipo = BEZT_IPO_BOUNCE;
@ -141,8 +149,10 @@ TEST(evaluate_fcurve, ExtrapolationLinearKeys)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); EXPECT_EQ(insert_vert_fcurve(fcu, {1.0f, 7.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); 0);
EXPECT_EQ(insert_vert_fcurve(fcu, {2.0f, 13.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
1);
fcu->bezt[0].ipo = BEZT_IPO_LIN; fcu->bezt[0].ipo = BEZT_IPO_LIN;
fcu->bezt[1].ipo = BEZT_IPO_LIN; fcu->bezt[1].ipo = BEZT_IPO_LIN;
@ -170,8 +180,10 @@ TEST(evaluate_fcurve, ExtrapolationBezierKeys)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); EXPECT_EQ(insert_vert_fcurve(fcu, {1.0f, 7.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); 0);
EXPECT_EQ(insert_vert_fcurve(fcu, {2.0f, 13.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
1);
fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */ fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */ fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
@ -207,8 +219,10 @@ TEST(fcurve_subdivide, BKE_fcurve_bezt_subdivide_handles)
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
/* Insert two keyframes and set handles to something non-default. */ /* Insert two keyframes and set handles to something non-default. */
EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); EXPECT_EQ(insert_vert_fcurve(fcu, {1.0f, 0.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
EXPECT_EQ(insert_vert_fcurve(fcu, 13.0f, 2.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); 0);
EXPECT_EQ(insert_vert_fcurve(fcu, {13.0f, 2.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
1);
fcu->bezt[0].h1 = fcu->bezt[0].h2 = HD_FREE; fcu->bezt[0].h1 = fcu->bezt[0].h2 = HD_FREE;
fcu->bezt[0].vec[0][0] = -5.0f; fcu->bezt[0].vec[0][0] = -5.0f;
@ -273,11 +287,14 @@ TEST(fcurve_active_keyframe, ActiveKeyframe)
EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), FCURVE_ACTIVE_KEYFRAME_NONE); EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), FCURVE_ACTIVE_KEYFRAME_NONE);
/* Check that adding new points sets the active index. */ /* Check that adding new points sets the active index. */
EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.5f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0); EXPECT_EQ(insert_vert_fcurve(fcu, {1.0f, 7.5f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
0);
EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 0); EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 0);
EXPECT_EQ(insert_vert_fcurve(fcu, 8.0f, 15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1); EXPECT_EQ(insert_vert_fcurve(fcu, {8.0f, 15.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
1);
EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 1); EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 1);
EXPECT_EQ(insert_vert_fcurve(fcu, 14.0f, 8.2f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 2); EXPECT_EQ(insert_vert_fcurve(fcu, {14.0f, 8.2f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF),
2);
EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 2); EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 2);
/* Check clearing the index. */ /* Check clearing the index. */
@ -325,9 +342,9 @@ TEST(BKE_fcurve, BKE_fcurve_keyframe_move_value_with_handles)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
insert_vert_fcurve(fcu, 1.0f, 7.5f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {1.0f, 7.5f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 8.0f, 15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {8.0f, 15.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 14.0f, 8.2f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {14.0f, 8.2f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f); EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f);
EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f); EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f);
@ -356,9 +373,9 @@ TEST(BKE_fcurve, BKE_fcurve_keyframe_move_time_with_handles)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
insert_vert_fcurve(fcu, 1.0f, 7.5f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {1.0f, 7.5f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 8.0f, 15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {8.0f, 15.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 14.0f, 8.2f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {14.0f, 8.2f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f); EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f);
EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f); EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f);
@ -387,11 +404,11 @@ TEST(BKE_fcurve, BKE_fcurve_calc_range)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
insert_vert_fcurve(fcu, 1.0f, 7.5f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {1.0f, 7.5f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 4.0f, -15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {4.0f, -15.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 8.0f, 15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {8.0f, 15.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 14.0f, 8.2f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {14.0f, 8.2f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 18.2f, -20.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {18.2f, -20.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
for (int i = 0; i < fcu->totvert; i++) { for (int i = 0; i < fcu->totvert; i++) {
fcu->bezt[i].f1 &= ~SELECT; fcu->bezt[i].f1 &= ~SELECT;
@ -439,11 +456,11 @@ TEST(BKE_fcurve, BKE_fcurve_calc_bounds)
{ {
FCurve *fcu = BKE_fcurve_create(); FCurve *fcu = BKE_fcurve_create();
insert_vert_fcurve(fcu, 1.0f, 7.5f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {1.0f, 7.5f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 4.0f, -15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {4.0f, -15.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 8.0f, 15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {8.0f, 15.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 14.0f, 8.2f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {14.0f, 8.2f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
insert_vert_fcurve(fcu, 18.2f, -20.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); insert_vert_fcurve(fcu, {18.2f, -20.0f}, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
for (int i = 0; i < fcu->totvert; i++) { for (int i = 0; i < fcu->totvert; i++) {
fcu->bezt[i].f1 &= ~SELECT; fcu->bezt[i].f1 &= ~SELECT;

View File

@ -25,6 +25,7 @@
#include "BLI_math_matrix.h" #include "BLI_math_matrix.h"
#include "BLI_math_rotation.h" #include "BLI_math_rotation.h"
#include "BLI_math_vector.h" #include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_math_vector_types.hh" #include "BLI_math_vector_types.hh"
#include "BLI_polyfill_2d.h" #include "BLI_polyfill_2d.h"
#include "BLI_span.hh" #include "BLI_span.hh"
@ -115,10 +116,9 @@ std::optional<blender::Bounds<blender::float3>> BKE_gpencil_data_minmax(const bG
void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3]) void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
{ {
const blender::Bounds<blender::float3> bounds = *BKE_gpencil_data_minmax(gpd); using namespace blender;
const Bounds<float3> bounds = BKE_gpencil_data_minmax(gpd).value_or(Bounds(float3(0)));
const float3 tot = bounds.min + bounds.max; copy_v3_v3(r_centroid, math::midpoint(bounds.min, bounds.max));
mul_v3_v3fl(r_centroid, tot, 0.5f);
} }
void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps) void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)

View File

@ -440,7 +440,7 @@ TEST(lib_id_main_unique_name, name_number_suffix_assignment)
EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain)); EXPECT_TRUE(BKE_main_namemap_validate(ctx.bmain));
/* Create objects again; they should get suffixes that were just free'd up. */ /* Create objects again; they should get suffixes that were just freed up. */
ID *id_010 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo")); ID *id_010 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
EXPECT_STREQ(id_010->name + 2, "Foo.010"); EXPECT_STREQ(id_010->name + 2, "Foo.010");
ID *id_020 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123")); ID *id_020 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123"));

View File

@ -740,19 +740,77 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
struct LibOverrideGroupTagData { struct LibOverrideGroupTagData {
Main *bmain; Main *bmain;
Scene *scene; Scene *scene;
ID *id_root;
ID *hierarchy_root_id; /** The linked data used as reference for the liboverrides. */
ID *id_root_reference;
ID *hierarchy_root_id_reference;
/** The existing liboverrides, if any. */
ID *id_root_override;
ID *hierarchy_root_id_override;
/**
* Whether we are looping on override data, or their references (linked) one.
*
* IMPORTANT: This value controls which of the `reference`/`override` ID pointers are accessed by
* the `root`/`hierarchy_root` accessor functions below. */
bool is_override;
ID *root_get()
{
return is_override ? id_root_override : id_root_reference;
}
void root_set(ID *id_root)
{
if (is_override) {
id_root_override = id_root;
}
else {
id_root_reference = id_root;
}
}
ID *hierarchy_root_get()
{
return is_override ? hierarchy_root_id_override : hierarchy_root_id_reference;
}
void hierarchy_root_set(ID *hierarchy_root_id)
{
if (is_override) {
hierarchy_root_id_override = hierarchy_root_id;
}
else {
hierarchy_root_id_reference = hierarchy_root_id;
}
}
/** Whether we are creating new override, or resyncing existing one. */
bool is_resync;
/** ID tag to use for IDs detected as being part of the liboverride hierarchy. */
uint tag; uint tag;
uint missing_tag; uint missing_tag;
/* Whether we are looping on override data, or their references (linked) one. */
bool is_override;
/* Whether we are creating new override, or resyncing existing one. */
bool is_resync;
/* Mapping linked objects to all their instantiating collections (as a linked list). /* Mapping linked objects to all their instantiating collections (as a linked list).
* Avoids calling #BKE_collection_object_find over and over, this function is very expansive. */ * Avoids calling #BKE_collection_object_find over and over, this function is very expansive. */
GHash *linked_object_to_instantiating_collections; GHash *linked_object_to_instantiating_collections;
MemArena *mem_arena; MemArena *mem_arena;
void clear(void)
{
BLI_ghash_free(linked_object_to_instantiating_collections, nullptr, nullptr);
BLI_memarena_free(mem_arena);
bmain = nullptr;
scene = nullptr;
id_root_reference = nullptr;
hierarchy_root_id_reference = nullptr;
id_root_override = nullptr;
hierarchy_root_id_override = nullptr;
tag = 0;
missing_tag = 0;
is_override = false;
is_resync = false;
}
}; };
static void lib_override_group_tag_data_object_to_collection_init_collection_process( static void lib_override_group_tag_data_object_to_collection_init_collection_process(
@ -796,17 +854,10 @@ static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGro
} }
} }
static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data)
{
BLI_ghash_free(data->linked_object_to_instantiating_collections, nullptr, nullptr);
BLI_memarena_free(data->mem_arena);
memset(data, 0, sizeof(*data));
}
static void lib_override_hierarchy_dependencies_recursive_tag_from(LibOverrideGroupTagData *data) static void lib_override_hierarchy_dependencies_recursive_tag_from(LibOverrideGroupTagData *data)
{ {
Main *bmain = data->bmain; Main *bmain = data->bmain;
ID *id = data->id_root; ID *id = data->root_get();
const bool is_override = data->is_override; const bool is_override = data->is_override;
if ((*reinterpret_cast<uint *>(&id->tag) & data->tag) == 0) { if ((*reinterpret_cast<uint *>(&id->tag) & data->tag) == 0) {
@ -844,22 +895,22 @@ static void lib_override_hierarchy_dependencies_recursive_tag_from(LibOverrideGr
continue; continue;
} }
from_id->tag |= data->tag; from_id->tag |= data->tag;
LibOverrideGroupTagData sub_data = *data; data->root_set(from_id);
sub_data.id_root = from_id; lib_override_hierarchy_dependencies_recursive_tag_from(data);
lib_override_hierarchy_dependencies_recursive_tag_from(&sub_data);
} }
data->root_set(id);
} }
/* Tag all IDs in dependency relationships within an override hierarchy/group. /* Tag all IDs in dependency relationships within an override hierarchy/group.
* *
* Requires existing `Main.relations`. * Requires existing `Main.relations`.
* *
* NOTE: This is typically called to complete `lib_override_linked_group_tag()`. * NOTE: This is typically called to complete #lib_override_linked_group_tag.
*/ */
static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTagData *data) static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTagData *data)
{ {
Main *bmain = data->bmain; Main *bmain = data->bmain;
ID *id = data->id_root; ID *id = data->root_get();
const bool is_override = data->is_override; const bool is_override = data->is_override;
const bool is_resync = data->is_resync; const bool is_resync = data->is_resync;
@ -891,12 +942,12 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
* both barriers of dependency. */ * both barriers of dependency. */
continue; continue;
} }
LibOverrideGroupTagData sub_data = *data; data->root_set(to_id);
sub_data.id_root = to_id; if (lib_override_hierarchy_dependencies_recursive_tag(data)) {
if (lib_override_hierarchy_dependencies_recursive_tag(&sub_data)) {
id->tag |= data->tag; id->tag |= data->tag;
} }
} }
data->root_set(id);
/* If the current ID is/has been tagged for override above, then check its reversed dependencies /* If the current ID is/has been tagged for override above, then check its reversed dependencies
* (i.e. IDs that depend on the current one). * (i.e. IDs that depend on the current one).
@ -913,7 +964,7 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *data) static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *data)
{ {
Main *bmain = data->bmain; Main *bmain = data->bmain;
ID *id_owner = data->id_root; ID *id_owner = data->root_get();
BLI_assert(ID_IS_LINKED(id_owner)); BLI_assert(ID_IS_LINKED(id_owner));
BLI_assert(!data->is_override); BLI_assert(!data->is_override);
const uint tag = data->tag; const uint tag = data->tag;
@ -962,10 +1013,10 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
} }
/* Recursively process the dependencies. */ /* Recursively process the dependencies. */
LibOverrideGroupTagData sub_data = *data; data->root_set(to_id);
sub_data.id_root = to_id; lib_override_linked_group_tag_recursive(data);
lib_override_linked_group_tag_recursive(&sub_data);
} }
data->root_set(id_owner);
} }
static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursive( static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursive(
@ -1007,11 +1058,14 @@ static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursiv
static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGroupTagData *data) static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGroupTagData *data)
{ {
Main *bmain = data->bmain; Main *bmain = data->bmain;
ID *id_root = data->id_root; ID *id_root = data->root_get();
/* Remove (untag) bone shape objects, they shall never need to be to directly/explicitly /* Remove (untag) bone shape objects, they shall never need to be to directly/explicitly
* overridden. */ * overridden. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) { LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob->id.lib != id_root->lib) {
continue;
}
if (ob->type == OB_ARMATURE && ob->pose != nullptr && (ob->id.tag & data->tag)) { if (ob->type == OB_ARMATURE && ob->pose != nullptr && (ob->id.tag & data->tag)) {
for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first); for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first);
pchan != nullptr; pchan != nullptr;
@ -1027,7 +1081,9 @@ static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGr
/* Remove (untag) collections if they do not own any tagged object (either themselves, or in /* Remove (untag) collections if they do not own any tagged object (either themselves, or in
* their children collections). */ * their children collections). */
LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
if ((collection->id.tag & data->tag) == 0 || &collection->id == id_root) { if ((collection->id.tag & data->tag) == 0 || &collection->id == id_root ||
collection->id.lib != id_root->lib)
{
continue; continue;
} }
@ -1050,18 +1106,17 @@ static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGr
static void lib_override_linked_group_tag(LibOverrideGroupTagData *data) static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
{ {
Main *bmain = data->bmain; Main *bmain = data->bmain;
ID *id_root = data->id_root; ID *id_root = data->root_get();
const bool is_resync = data->is_resync; const bool is_resync = data->is_resync;
BLI_assert(!data->is_override); BLI_assert(!data->is_override);
if (id_root->tag & LIB_TAG_MISSING) { if (id_root->tag & LIB_TAG_MISSING) {
id_root->tag |= data->missing_tag; id_root->tag |= data->missing_tag;
} return;
else {
id_root->tag |= data->tag;
} }
/* Tag all collections and objects recursively. */ /* Tag all collections and objects recursively. */
id_root->tag |= data->tag;
lib_override_linked_group_tag_recursive(data); lib_override_linked_group_tag_recursive(data);
/* Do not override objects used as bone shapes, nor their collections if possible. */ /* Do not override objects used as bone shapes, nor their collections if possible. */
@ -1133,11 +1188,11 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *data) static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *data)
{ {
Main *bmain = data->bmain; Main *bmain = data->bmain;
ID *id_owner = data->id_root; ID *id_owner = data->root_get();
BLI_assert(ID_IS_OVERRIDE_LIBRARY(id_owner)); BLI_assert(ID_IS_OVERRIDE_LIBRARY(id_owner));
BLI_assert(data->is_override); BLI_assert(data->is_override);
ID *id_hierarchy_root = data->hierarchy_root_id; ID *id_hierarchy_root = data->hierarchy_root_get();
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_owner) && if (ID_IS_OVERRIDE_LIBRARY_REAL(id_owner) &&
(id_owner->override_library->flag & LIBOVERRIDE_FLAG_NO_HIERARCHY) != 0) (id_owner->override_library->flag & LIBOVERRIDE_FLAG_NO_HIERARCHY) != 0)
@ -1200,20 +1255,20 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
} }
/* Recursively process the dependencies. */ /* Recursively process the dependencies. */
LibOverrideGroupTagData sub_data = *data; data->root_set(to_id);
sub_data.id_root = to_id; lib_override_overrides_group_tag_recursive(data);
lib_override_overrides_group_tag_recursive(&sub_data);
} }
data->root_set(id_owner);
} }
/* This will tag all override IDs of an override group defined by the given `id_root`. */ /* This will tag all override IDs of an override group defined by the given `id_root`. */
static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data) static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data)
{ {
ID *id_root = data->id_root; ID *id_root = data->root_get();
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root)); BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
BLI_assert(data->is_override); BLI_assert(data->is_override);
ID *id_hierarchy_root = data->hierarchy_root_id; ID *id_hierarchy_root = data->hierarchy_root_get();
BLI_assert(id_hierarchy_root != nullptr); BLI_assert(id_hierarchy_root != nullptr);
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root)); BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root));
UNUSED_VARS_NDEBUG(id_hierarchy_root); UNUSED_VARS_NDEBUG(id_hierarchy_root);
@ -1240,11 +1295,13 @@ static bool lib_override_library_create_do(Main *bmain,
LibOverrideGroupTagData data{}; LibOverrideGroupTagData data{};
data.bmain = bmain; data.bmain = bmain;
data.scene = scene; data.scene = scene;
data.id_root = id_root_reference;
data.tag = LIB_TAG_DOIT; data.tag = LIB_TAG_DOIT;
data.missing_tag = LIB_TAG_MISSING; data.missing_tag = LIB_TAG_MISSING;
data.is_override = false; data.is_override = false;
data.is_resync = false; data.is_resync = false;
data.root_set(id_root_reference);
lib_override_group_tag_data_object_to_collection_init(&data); lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_linked_group_tag(&data); lib_override_linked_group_tag(&data);
@ -1260,14 +1317,14 @@ static bool lib_override_library_create_do(Main *bmain,
id_root_reference->lib); id_root_reference->lib);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
data.hierarchy_root_id = id_hierarchy_root_reference;
data.id_root = id_hierarchy_root_reference;
data.is_override = true; data.is_override = true;
data.root_set(id_hierarchy_root_reference);
data.hierarchy_root_set(id_hierarchy_root_reference);
lib_override_overrides_group_tag(&data); lib_override_overrides_group_tag(&data);
} }
BKE_main_relations_free(bmain); BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data); data.clear();
bool success = false; bool success = false;
if (id_hierarchy_root_reference->lib != id_root_reference->lib) { if (id_hierarchy_root_reference->lib != id_root_reference->lib) {
@ -1402,6 +1459,10 @@ static void lib_override_library_create_post_process(Main *bmain,
ob_new->id.override_library->reference == &ob->id); ob_new->id.override_library->reference == &ob->id);
if (old_active_object == ob) { if (old_active_object == ob) {
BLI_assert(view_layer);
/* May have been tagged as dirty again in a previous iteration of this loop, e.g. if adding a
* liboverride object to a collection. */
BKE_view_layer_synced_ensure(scene, view_layer);
Base *basact = BKE_view_layer_base_find(view_layer, ob_new); Base *basact = BKE_view_layer_base_find(view_layer, ob_new);
if (basact != nullptr) { if (basact != nullptr) {
view_layer->basact = basact; view_layer->basact = basact;
@ -1991,12 +2052,14 @@ static bool lib_override_library_resync(Main *bmain,
LibOverrideGroupTagData data{}; LibOverrideGroupTagData data{};
data.bmain = bmain; data.bmain = bmain;
data.scene = scene; data.scene = scene;
data.id_root = id_root;
data.hierarchy_root_id = id_root->override_library->hierarchy_root;
data.tag = LIB_TAG_DOIT; data.tag = LIB_TAG_DOIT;
data.missing_tag = LIB_TAG_MISSING; data.missing_tag = LIB_TAG_MISSING;
data.is_override = true; data.is_override = true;
data.is_resync = true; data.is_resync = true;
data.root_set(id_root);
data.hierarchy_root_set(id_root->override_library->hierarchy_root);
lib_override_group_tag_data_object_to_collection_init(&data); lib_override_group_tag_data_object_to_collection_init(&data);
/* Mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, populated from /* Mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, populated from
@ -2038,20 +2101,20 @@ static bool lib_override_library_resync(Main *bmain,
id_root->name + 2); id_root->name + 2);
BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr); BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr);
BKE_main_relations_free(bmain); BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data); data.clear();
return false; return false;
} }
/* Tag local overrides of the current resync sub-hierarchy. */ /* Tag local overrides of the current resync sub-hierarchy. */
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
data.id_root = id_resync_root;
data.is_override = true; data.is_override = true;
data.root_set(id_resync_root);
lib_override_overrides_group_tag(&data); lib_override_overrides_group_tag(&data);
/* Tag reference data matching the current resync sub-hierarchy. */ /* Tag reference data matching the current resync sub-hierarchy. */
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
data.id_root = id_resync_root->override_library->reference;
data.is_override = false; data.is_override = false;
data.root_set(id_resync_root->override_library->reference);
lib_override_linked_group_tag(&data); lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@ -2150,12 +2213,12 @@ static bool lib_override_library_resync(Main *bmain,
/* Tag all local overrides of the current hierarchy. */ /* Tag all local overrides of the current hierarchy. */
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
data.id_root = id_root;
data.is_override = true; data.is_override = true;
data.root_set(id_root);
lib_override_overrides_group_tag(&data); lib_override_overrides_group_tag(&data);
BKE_main_relations_free(bmain); BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data); data.clear();
/* Make new override from linked data. */ /* Make new override from linked data. */
/* Note that this call also remaps all pointers of tagged IDs from old override IDs to new /* Note that this call also remaps all pointers of tagged IDs from old override IDs to new
@ -3080,7 +3143,6 @@ static bool lib_override_library_main_resync_on_library_indirect_level(
LibOverrideGroupTagData data = {}; LibOverrideGroupTagData data = {};
data.bmain = bmain; data.bmain = bmain;
data.scene = scene; data.scene = scene;
data.id_root = nullptr;
data.tag = LIB_TAG_DOIT; data.tag = LIB_TAG_DOIT;
data.missing_tag = LIB_TAG_MISSING; data.missing_tag = LIB_TAG_MISSING;
data.is_override = false; data.is_override = false;
@ -3097,14 +3159,14 @@ static bool lib_override_library_main_resync_on_library_indirect_level(
continue; continue;
} }
data.id_root = id->override_library->reference; data.root_set(id->override_library->reference);
lib_override_linked_group_tag(&data); lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data); lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
} }
FOREACH_MAIN_ID_END; FOREACH_MAIN_ID_END;
lib_override_group_tag_data_clear(&data); data.clear();
GHash *id_roots = BLI_ghash_ptr_new(__func__); GHash *id_roots = BLI_ghash_ptr_new(__func__);
@ -3569,17 +3631,19 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
LibOverrideGroupTagData data{}; LibOverrideGroupTagData data{};
data.bmain = bmain; data.bmain = bmain;
data.scene = nullptr; data.scene = nullptr;
data.id_root = id_root;
data.hierarchy_root_id = id_root->override_library->hierarchy_root;
data.tag = LIB_TAG_DOIT; data.tag = LIB_TAG_DOIT;
data.missing_tag = LIB_TAG_MISSING; data.missing_tag = LIB_TAG_MISSING;
data.is_override = true; data.is_override = true;
data.is_resync = false; data.is_resync = false;
data.root_set(id_root);
data.hierarchy_root_set(id_root->override_library->hierarchy_root);
lib_override_group_tag_data_object_to_collection_init(&data); lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data); lib_override_overrides_group_tag(&data);
BKE_main_relations_free(bmain); BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data); data.clear();
ID *id; ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) { FOREACH_MAIN_ID_BEGIN (bmain, id) {

View File

@ -298,7 +298,7 @@ static void main_merge_add_id_to_move(Main *bmain_dst,
void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &reports) void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &reports)
{ {
Main *bmain_src = *r_bmain_src; Main *bmain_src = *r_bmain_src;
/* NOTE: Dedicated mapping type is needed here, to handle propoerly the library cases. */ /* NOTE: Dedicated mapping type is needed here, to handle properly the library cases. */
blender::Map<std::string, blender::Vector<ID *>> id_map_dst; blender::Map<std::string, blender::Vector<ID *>> id_map_dst;
ID *id_iter_dst, *id_iter_src; ID *id_iter_dst, *id_iter_src;
FOREACH_MAIN_ID_BEGIN (bmain_dst, id_iter_dst) { FOREACH_MAIN_ID_BEGIN (bmain_dst, id_iter_dst) {

View File

@ -212,7 +212,7 @@ TEST_F(BMainMergeTest, linked_data)
/* Use a relative library path. Since this is a different library, even though the object re-use /* Use a relative library path. Since this is a different library, even though the object re-use
* the same name, it should still be moved into `bmain_dst`. The library filepath should also be * the same name, it should still be moved into `bmain_dst`. The library filepath should also be
* updated and become relative the the path of bmain_dst too. */ * updated and become relative the path of bmain_dst too. */
bmain_src = BKE_main_new(); bmain_src = BKE_main_new();
BLI_strncpy(bmain_src->filepath, SRC_PATH, sizeof(bmain_dst->filepath)); BLI_strncpy(bmain_src->filepath, SRC_PATH, sizeof(bmain_dst->filepath));

View File

@ -963,7 +963,7 @@ static void vnormal(PROCESS *process, const float point[3], float r_no[3])
r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f; r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f;
r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f; r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f;
} }
#endif /* USE_ACCUM_NORMAL */ #endif /* !USE_ACCUM_NORMAL */
/** /**
* \return the id of vertex between two corners. * \return the id of vertex between two corners.

View File

@ -535,7 +535,7 @@ void BKE_mesh_face_offsets_ensure_alloc(Mesh *mesh)
mesh->runtime->face_offsets_sharing_info = blender::implicit_sharing::info_for_mem_free( mesh->runtime->face_offsets_sharing_info = blender::implicit_sharing::info_for_mem_free(
mesh->face_offset_indices); mesh->face_offset_indices);
#ifdef DEBUG #ifndef NDEBUG
/* Fill offsets with obviously bad values to simplify finding missing initialization. */ /* Fill offsets with obviously bad values to simplify finding missing initialization. */
mesh->face_offsets_for_write().fill(-1); mesh->face_offsets_for_write().fill(-1);
#endif #endif
@ -790,7 +790,7 @@ void BKE_mesh_texspace_calc(Mesh *me)
using namespace blender; using namespace blender;
if (me->texspace_flag & ME_TEXSPACE_FLAG_AUTO) { if (me->texspace_flag & ME_TEXSPACE_FLAG_AUTO) {
const Bounds<float3> bounds = me->bounds_min_max().value_or( const Bounds<float3> bounds = me->bounds_min_max().value_or(
Bounds<float3>{float3(-1.0f), float3(1.0f)}); Bounds(float3(-1.0f), float3(1.0f)));
float texspace_location[3], texspace_size[3]; float texspace_location[3], texspace_size[3];
mid_v3_v3v3(texspace_location, bounds.min, bounds.max); mid_v3_v3v3(texspace_location, bounds.min, bounds.max);

View File

@ -82,4 +82,4 @@ void BKE_mesh_debug_print(const Mesh *me)
MEM_freeN(str); MEM_freeN(str);
} }
#endif /* NDEBUG */ #endif /* !NDEBUG */

View File

@ -510,6 +510,8 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
/** \name Visibility Interpolation /** \name Visibility Interpolation
* \{ */ * \{ */
namespace blender::bke {
/* Hide edges when either of their vertices are hidden. */ /* Hide edges when either of their vertices are hidden. */
static void edge_hide_from_vert(const Span<int2> edges, static void edge_hide_from_vert(const Span<int2> edges,
const Span<bool> hide_vert, const Span<bool> hide_vert,
@ -539,11 +541,9 @@ static void face_hide_from_vert(const OffsetIndices<int> faces,
}); });
} }
void BKE_mesh_flush_hidden_from_verts(Mesh *me) void mesh_hide_vert_flush(Mesh &mesh)
{ {
using namespace blender; MutableAttributeAccessor attributes = mesh.attributes_for_write();
using namespace blender::bke;
MutableAttributeAccessor attributes = me->attributes_for_write();
const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>( const VArray<bool> hide_vert = *attributes.lookup_or_default<bool>(
".hide_vert", ATTR_DOMAIN_POINT, false); ".hide_vert", ATTR_DOMAIN_POINT, false);
@ -559,18 +559,16 @@ void BKE_mesh_flush_hidden_from_verts(Mesh *me)
SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>(
".hide_poly", ATTR_DOMAIN_FACE); ".hide_poly", ATTR_DOMAIN_FACE);
edge_hide_from_vert(me->edges(), hide_vert_span, hide_edge.span); edge_hide_from_vert(mesh.edges(), hide_vert_span, hide_edge.span);
face_hide_from_vert(me->faces(), me->corner_verts(), hide_vert_span, hide_poly.span); face_hide_from_vert(mesh.faces(), mesh.corner_verts(), hide_vert_span, hide_poly.span);
hide_edge.finish(); hide_edge.finish();
hide_poly.finish(); hide_poly.finish();
} }
void BKE_mesh_flush_hidden_from_faces(Mesh *me) void mesh_hide_face_flush(Mesh &mesh)
{ {
using namespace blender; MutableAttributeAccessor attributes = mesh.attributes_for_write();
using namespace blender::bke;
MutableAttributeAccessor attributes = me->attributes_for_write();
const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>( const VArray<bool> hide_poly = *attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false); ".hide_poly", ATTR_DOMAIN_FACE, false);
@ -580,9 +578,9 @@ void BKE_mesh_flush_hidden_from_faces(Mesh *me)
return; return;
} }
const VArraySpan<bool> hide_poly_span{hide_poly}; const VArraySpan<bool> hide_poly_span{hide_poly};
const OffsetIndices faces = me->faces(); const OffsetIndices faces = mesh.faces();
const Span<int> corner_verts = me->corner_verts(); const Span<int> corner_verts = mesh.corner_verts();
const Span<int> corner_edges = me->corner_edges(); const Span<int> corner_edges = mesh.corner_edges();
SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_only_span<bool>( SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_only_span<bool>(
".hide_vert", ATTR_DOMAIN_POINT); ".hide_vert", ATTR_DOMAIN_POINT);
SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>( SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>(
@ -617,11 +615,9 @@ void BKE_mesh_flush_hidden_from_faces(Mesh *me)
/** \name Selection Interpolation /** \name Selection Interpolation
* \{ */ * \{ */
void BKE_mesh_flush_select_from_faces(Mesh *me) void mesh_select_face_flush(Mesh &mesh)
{ {
using namespace blender; MutableAttributeAccessor attributes = mesh.attributes_for_write();
using namespace blender::bke;
MutableAttributeAccessor attributes = me->attributes_for_write();
const VArray<bool> select_poly = *attributes.lookup_or_default<bool>( const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
".select_poly", ATTR_DOMAIN_FACE, false); ".select_poly", ATTR_DOMAIN_FACE, false);
if (select_poly.is_single() && !select_poly.get_internal_single()) { if (select_poly.is_single() && !select_poly.get_internal_single()) {
@ -645,11 +641,9 @@ void BKE_mesh_flush_select_from_faces(Mesh *me)
select_edge.finish(); select_edge.finish();
} }
void BKE_mesh_flush_select_from_verts(Mesh *me) void mesh_select_vert_flush(Mesh &mesh)
{ {
using namespace blender; MutableAttributeAccessor attributes = mesh.attributes_for_write();
using namespace blender::bke;
MutableAttributeAccessor attributes = me->attributes_for_write();
const VArray<bool> select_vert = *attributes.lookup_or_default<bool>( const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false); ".select_vert", ATTR_DOMAIN_POINT, false);
if (select_vert.is_single() && !select_vert.get_internal_single()) { if (select_vert.is_single() && !select_vert.get_internal_single()) {
@ -683,11 +677,9 @@ void BKE_mesh_flush_select_from_verts(Mesh *me)
select_poly.finish(); select_poly.finish();
} }
void BKE_mesh_flush_select_from_edges(Mesh *me) void mesh_select_edge_flush(Mesh &mesh)
{ {
using namespace blender; MutableAttributeAccessor attributes = mesh.attributes_for_write();
using namespace blender::bke;
MutableAttributeAccessor attributes = me->attributes_for_write();
const VArray<bool> select_edge = *attributes.lookup_or_default<bool>( const VArray<bool> select_edge = *attributes.lookup_or_default<bool>(
".select_edge", ATTR_DOMAIN_POINT, false); ".select_edge", ATTR_DOMAIN_POINT, false);
if (select_edge.is_single() && !select_edge.get_internal_single()) { if (select_edge.is_single() && !select_edge.get_internal_single()) {
@ -721,6 +713,8 @@ void BKE_mesh_flush_select_from_edges(Mesh *me)
select_poly.finish(); select_poly.finish();
} }
} // namespace blender::bke
/** \} */ /** \} */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */

View File

@ -23,8 +23,8 @@
#include "BKE_mesh_fair.hh" #include "BKE_mesh_fair.hh"
#include "BKE_mesh_mapping.hh" #include "BKE_mesh_mapping.hh"
#include "bmesh.h" #include "bmesh.hh"
#include "bmesh_tools.h" #include "bmesh_tools.hh"
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
#include "eigen_capi.h" #include "eigen_capi.h"
@ -207,7 +207,7 @@ class MeshFairingContext : public FairingContext {
vlmap_ = mesh->vert_to_corner_map(); vlmap_ = mesh->vert_to_corner_map();
/* Deformation coords. */ /* Deformation coords. */
co_.reserve(mesh->totvert); co_.resize(mesh->totvert);
if (!deform_positions.is_empty()) { if (!deform_positions.is_empty()) {
for (int i = 0; i < mesh->totvert; i++) { for (int i = 0; i < mesh->totvert; i++) {
co_[i] = deform_positions[i]; co_[i] = deform_positions[i];
@ -261,7 +261,7 @@ class BMeshFairingContext : public FairingContext {
BM_mesh_elem_index_ensure(bm, BM_LOOP); BM_mesh_elem_index_ensure(bm, BM_LOOP);
/* Deformation coords. */ /* Deformation coords. */
co_.reserve(bm->totvert); co_.resize(bm->totvert);
for (int i = 0; i < bm->totvert; i++) { for (int i = 0; i < bm->totvert; i++) {
BMVert *v = BM_vert_at_index(bm, i); BMVert *v = BM_vert_at_index(bm, i);
co_[i] = v->co; co_[i] = v->co;
@ -319,7 +319,7 @@ class UniformVertexWeight : public VertexWeight {
UniformVertexWeight(FairingContext *fairing_context) UniformVertexWeight(FairingContext *fairing_context)
{ {
const int totvert = fairing_context->vertex_count_get(); const int totvert = fairing_context->vertex_count_get();
vertex_weights_.reserve(totvert); vertex_weights_.resize(totvert);
for (int i = 0; i < totvert; i++) { for (int i = 0; i < totvert; i++) {
const int tot_loop = fairing_context->vertex_loop_map_get(i).size(); const int tot_loop = fairing_context->vertex_loop_map_get(i).size();
if (tot_loop != 0) { if (tot_loop != 0) {
@ -347,7 +347,7 @@ class VoronoiVertexWeight : public VertexWeight {
{ {
const int totvert = fairing_context->vertex_count_get(); const int totvert = fairing_context->vertex_count_get();
vertex_weights_.reserve(totvert); vertex_weights_.resize(totvert);
for (int i = 0; i < totvert; i++) { for (int i = 0; i < totvert; i++) {
float area = 0.0f; float area = 0.0f;

View File

@ -650,7 +650,7 @@ static bool check_matching_legacy_layer_counts(CustomData *fdata_legacy,
* then there was nothing to do... */ * then there was nothing to do... */
return a_num ? true : fallback; return a_num ? true : fallback;
} }
#endif #endif /* !NDEBUG */
static void add_mface_layers(Mesh &mesh, CustomData *fdata_legacy, CustomData *ldata, int total) static void add_mface_layers(Mesh &mesh, CustomData *fdata_legacy, CustomData *ldata, int total)
{ {

View File

@ -23,8 +23,8 @@
#include "BKE_mesh_mirror.hh" #include "BKE_mesh_mirror.hh"
#include "BKE_modifier.hh" #include "BKE_modifier.hh"
#include "bmesh.h" #include "bmesh.hh"
#include "bmesh_tools.h" #include "bmesh_tools.hh"
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"

View File

@ -39,7 +39,7 @@
#include "BKE_mesh_runtime.hh" #include "BKE_mesh_runtime.hh"
#include "BKE_mesh_sample.hh" #include "BKE_mesh_sample.hh"
#include "bmesh_tools.h" #include "bmesh_tools.hh"
#ifdef WITH_OPENVDB #ifdef WITH_OPENVDB
# include <openvdb/openvdb.h> # include <openvdb/openvdb.h>

View File

@ -473,6 +473,6 @@ bool BKE_mesh_runtime_is_valid(Mesh *me_eval)
return is_valid; return is_valid;
} }
#endif /* NDEBUG */ #endif /* !NDEBUG */
/** \} */ /** \} */

View File

@ -74,7 +74,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
me->edit_mesh->is_shallow_copy = true; me->edit_mesh->is_shallow_copy = true;
/* Make sure we crash if these are ever used. */ /* Make sure we crash if these are ever used. */
#ifdef DEBUG #ifndef NDEBUG
me->totvert = INT_MAX; me->totvert = INT_MAX;
me->totedge = INT_MAX; me->totedge = INT_MAX;
me->faces_num = INT_MAX; me->faces_num = INT_MAX;

View File

@ -29,7 +29,7 @@
#include "BKE_subdiv.hh" #include "BKE_subdiv.hh"
#include "BKE_subsurf.hh" #include "BKE_subsurf.hh"
#include "bmesh.h" #include "bmesh.hh"
#include "DEG_depsgraph_query.hh" #include "DEG_depsgraph_query.hh"

View File

@ -3413,7 +3413,7 @@ static void free_localized_node_groups(bNodeTree *ntree)
{ {
/* Only localized node trees store a copy for each node group tree. /* Only localized node trees store a copy for each node group tree.
* Each node group tree in a localized node tree can be freed, * Each node group tree in a localized node tree can be freed,
* since it is a localized copy itself (no risk of accessing free'd * since it is a localized copy itself (no risk of accessing freed
* data in main, see #37939). */ * data in main, see #37939). */
if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) { if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) {
return; return;

View File

@ -512,7 +512,7 @@ class NodeTreeMainUpdater {
result.interface_changed = true; result.interface_changed = true;
} }
#ifdef DEBUG #ifndef NDEBUG
/* Check the uniqueness of node identifiers. */ /* Check the uniqueness of node identifiers. */
Set<int32_t> node_identifiers; Set<int32_t> node_identifiers;
const Span<const bNode *> nodes = ntree.all_nodes(); const Span<const bNode *> nodes = ntree.all_nodes();

View File

@ -73,7 +73,7 @@
#include "BLO_read_write.hh" #include "BLO_read_write.hh"
#include "bmesh.h" #include "bmesh.hh"
using blender::float3; using blender::float3;
using blender::MutableSpan; using blender::MutableSpan;
@ -773,15 +773,6 @@ void BKE_paint_palette_set(Paint *p, Palette *palette)
} }
} }
void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
{
if (br) {
id_us_min((ID *)br->paint_curve);
br->paint_curve = pc;
id_us_plus((ID *)br->paint_curve);
}
}
void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_index) void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_index)
{ {
pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0; pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0;
@ -1121,7 +1112,7 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
(Paint *)ts->uvsculpt, (Paint *)ts->uvsculpt,
(Paint *)ts->curves_sculpt, (Paint *)ts->curves_sculpt,
(Paint *)&ts->imapaint)); (Paint *)&ts->imapaint));
#ifdef DEBUG #ifndef NDEBUG
Paint paint_test = **r_paint; Paint paint_test = **r_paint;
BKE_paint_runtime_init(ts, *r_paint); BKE_paint_runtime_init(ts, *r_paint);
/* Swap so debug doesn't hide errors when release fails. */ /* Swap so debug doesn't hide errors when release fails. */
@ -1736,15 +1727,14 @@ static void sculpt_update_object(Depsgraph *depsgraph,
/* Sculpt Face Sets. */ /* Sculpt Face Sets. */
if (use_face_sets) { if (use_face_sets) {
ss->face_sets = static_cast<int *>(CustomData_get_layer_named_for_write( ss->face_sets = static_cast<const int *>(
&me->face_data, CD_PROP_INT32, ".sculpt_face_set", me->faces_num)); CustomData_get_layer_named(&me->face_data, CD_PROP_INT32, ".sculpt_face_set"));
} }
else { else {
ss->face_sets = nullptr; ss->face_sets = nullptr;
} }
ss->hide_poly = (bool *)CustomData_get_layer_named_for_write( ss->hide_poly = (bool *)CustomData_get_layer_named(&me->face_data, CD_PROP_BOOL, ".hide_poly");
&me->face_data, CD_PROP_BOOL, ".hide_poly", me->faces_num);
ss->subdiv_ccg = me_eval->runtime->subdiv_ccg.get(); ss->subdiv_ccg = me_eval->runtime->subdiv_ccg.get();
@ -1940,63 +1930,11 @@ void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bo
sculpt_update_object(depsgraph, ob_orig, ob_eval, is_paint_tool); sculpt_update_object(depsgraph, ob_orig, ob_eval, is_paint_tool);
} }
int *BKE_sculpt_face_sets_ensure(Object *ob) void BKE_sculpt_hide_poly_pointer_update(Object &object)
{ {
using namespace blender; const Mesh &mesh = *static_cast<const Mesh *>(object.data);
using namespace blender::bke; object.sculpt->hide_poly = static_cast<const bool *>(
Mesh *mesh = static_cast<Mesh *>(ob->data); CustomData_get_layer_named(&mesh.face_data, CD_PROP_BOOL, ".hide_poly"));
SculptSession *ss = ob->sculpt;
PBVH *pbvh = ss->pbvh;
if (!pbvh) {
BLI_assert_unreachable();
return nullptr;
}
const StringRefNull name = ".sculpt_face_set";
switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES:
case PBVH_GRIDS: {
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (!attributes.contains(name)) {
attributes.add<int>(name,
ATTR_DOMAIN_FACE,
AttributeInitVArray(VArray<int>::ForSingle(1, mesh->faces_num)));
mesh->face_sets_color_default = 1;
}
return static_cast<int *>(CustomData_get_layer_named_for_write(
&mesh->face_data, CD_PROP_INT32, name.c_str(), mesh->faces_num));
}
case PBVH_BMESH: {
BMesh *bm = BKE_pbvh_get_bmesh(pbvh);
if (!CustomData_has_layer_named(&bm->pdata, CD_PROP_INT32, name.c_str())) {
BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT32, name.c_str());
const int offset = CustomData_get_offset_named(&bm->pdata, CD_PROP_INT32, name.c_str());
if (offset == -1) {
return nullptr;
}
BMIter iter;
BMFace *face;
BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
BM_ELEM_CD_SET_INT(face, offset, 1);
}
mesh->face_sets_color_default = 1;
}
break;
}
}
return nullptr;
}
bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh)
{
bool *hide_poly = static_cast<bool *>(CustomData_get_layer_named_for_write(
&mesh->face_data, CD_PROP_BOOL, ".hide_poly", mesh->faces_num));
if (hide_poly != nullptr) {
return hide_poly;
}
return static_cast<bool *>(CustomData_add_layer_named(
&mesh->face_data, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->faces_num, ".hide_poly"));
} }
void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
@ -2601,22 +2539,6 @@ static SculptAttribute *sculpt_get_cached_layer(SculptSession *ss,
return nullptr; return nullptr;
} }
bool BKE_sculpt_attribute_exists(Object *ob,
eAttrDomain domain,
eCustomDataType proptype,
const char *name)
{
SculptSession *ss = ob->sculpt;
SculptAttribute *attr = sculpt_get_cached_layer(ss, domain, proptype, name);
if (attr) {
return true;
}
CustomData *cdata = sculpt_get_cdata(ob, domain);
return CustomData_get_named_layer_index(cdata, proptype, name) != -1;
}
static SculptAttribute *sculpt_alloc_attr(SculptSession *ss) static SculptAttribute *sculpt_alloc_attr(SculptSession *ss)
{ {
for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) {

View File

@ -41,7 +41,7 @@
#include "PIL_time.h" #include "PIL_time.h"
#include "bmesh.h" #include "bmesh.hh"
#include "atomic_ops.h" #include "atomic_ops.h"
@ -1811,9 +1811,8 @@ blender::Span<int> BKE_pbvh_node_get_unique_vert_indices(const PBVHNode *node)
return node->vert_indices.as_span().take_front(node->uniq_verts); return node->vert_indices.as_span().take_front(node->uniq_verts);
} }
blender::Vector<int> BKE_pbvh_node_calc_face_indices(const PBVH &pbvh, const PBVHNode &node) void BKE_pbvh_node_calc_face_indices(const PBVH &pbvh, const PBVHNode &node, Vector<int> &faces)
{ {
Vector<int> faces;
switch (pbvh.header.type) { switch (pbvh.header.type) {
case PBVH_FACES: { case PBVH_FACES: {
const Span<int> looptri_faces = pbvh.looptri_faces; const Span<int> looptri_faces = pbvh.looptri_faces;
@ -1843,7 +1842,12 @@ blender::Vector<int> BKE_pbvh_node_calc_face_indices(const PBVH &pbvh, const PBV
BLI_assert_unreachable(); BLI_assert_unreachable();
break; break;
} }
}
blender::Vector<int> BKE_pbvh_node_calc_face_indices(const PBVH &pbvh, const PBVHNode &node)
{
Vector<int> faces;
BKE_pbvh_node_calc_face_indices(pbvh, node, faces);
return faces; return faces;
} }
@ -2667,12 +2671,15 @@ static blender::draw::pbvh::PBVH_GPU_Args pbvh_draw_args_init(const Mesh &mesh,
PBVH &pbvh, PBVH &pbvh,
const PBVHNode &node) const PBVHNode &node)
{ {
/* TODO: Use an explicit argument for the original mesh to avoid relying on #PBVH::mesh. */
blender::draw::pbvh::PBVH_GPU_Args args{}; blender::draw::pbvh::PBVH_GPU_Args args{};
args.pbvh_type = pbvh.header.type; args.pbvh_type = pbvh.header.type;
args.face_sets_color_default = mesh.face_sets_color_default; args.face_sets_color_default = pbvh.mesh ? pbvh.mesh->face_sets_color_default :
args.face_sets_color_seed = mesh.face_sets_color_seed; mesh.face_sets_color_default;
args.face_sets_color_seed = pbvh.mesh ? pbvh.mesh->face_sets_color_seed :
mesh.face_sets_color_seed;
args.active_color = mesh.active_color_attribute; args.active_color = mesh.active_color_attribute;
args.render_color = mesh.default_color_attribute; args.render_color = mesh.default_color_attribute;
@ -3206,7 +3213,7 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh)
using namespace blender::bke; using namespace blender::bke;
switch (pbvh->header.type) { switch (pbvh->header.type) {
case PBVH_FACES: { case PBVH_FACES: {
BKE_mesh_flush_hidden_from_verts(mesh); mesh_hide_vert_flush(*mesh);
break; break;
} }
case PBVH_BMESH: { case PBVH_BMESH: {
@ -3269,7 +3276,7 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh)
hide_poly.finish(); hide_poly.finish();
} }
BKE_mesh_flush_hidden_from_faces(mesh); mesh_hide_face_flush(*mesh);
break; break;
} }
} }

View File

@ -24,7 +24,7 @@
#include "DRW_pbvh.hh" #include "DRW_pbvh.hh"
#include "bmesh.h" #include "bmesh.hh"
#include "pbvh_intern.hh" #include "pbvh_intern.hh"
#include "PIL_time.h" #include "PIL_time.h"
@ -1117,7 +1117,7 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
static void copy_edge_data(BMesh &bm, BMEdge &dst, /*const*/ BMEdge &src) static void copy_edge_data(BMesh &bm, BMEdge &dst, /*const*/ BMEdge &src)
{ {
dst.head.hflag = src.head.hflag & ~BM_ELEM_TAG; dst.head.hflag = src.head.hflag & ~BM_ELEM_TAG;
CustomData_bmesh_copy_data(&bm.edata, &bm.edata, src.head.data, &dst.head.data); CustomData_bmesh_copy_block(bm.edata, src.head.data, &dst.head.data);
} }
/* Merge edge custom data from src to dst. */ /* Merge edge custom data from src to dst. */

View File

@ -32,7 +32,7 @@
#include "PIL_time.h" #include "PIL_time.h"
#include "bmesh.h" #include "bmesh.hh"
#include "atomic_ops.h" #include "atomic_ops.h"

View File

@ -67,7 +67,7 @@ struct rbCollisionShape;
struct rbConstraint; struct rbConstraint;
struct rbDynamicsWorld; struct rbDynamicsWorld;
struct rbRigidBody; struct rbRigidBody;
#endif #endif /* !WITH_BULLET */
/* ************************************** */ /* ************************************** */
/* Memory Management */ /* Memory Management */

View File

@ -116,7 +116,7 @@
#include "DRW_engine.h" #include "DRW_engine.h"
#include "bmesh.h" #include "bmesh.hh"
CurveMapping *BKE_sculpt_default_cavity_curve() CurveMapping *BKE_sculpt_default_cavity_curve()

View File

@ -25,7 +25,7 @@
#include "opensubdiv_capi.h" #include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h" #include "opensubdiv_converter_capi.h"
#include "bmesh_class.h" #include "bmesh_class.hh"
/* Enable work-around for non-working CPU evaluator when using bilinear scheme. /* Enable work-around for non-working CPU evaluator when using bilinear scheme.
* This forces Catmark scheme with all edges marked as infinitely sharp. */ * This forces Catmark scheme with all edges marked as infinitely sharp. */

View File

@ -2370,7 +2370,7 @@ int text_check_identifier_nodigit_unicode(const uint ch)
{ {
return (ch < 255 && text_check_identifier_nodigit(char(ch))); return (ch < 255 && text_check_identifier_nodigit(char(ch)));
} }
#endif /* WITH_PYTHON */ #endif /* !WITH_PYTHON */
bool text_check_whitespace(const char ch) bool text_check_whitespace(const char ch)
{ {

View File

@ -379,7 +379,7 @@ WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain,
WorkSpaceLayout *layout = MEM_cnew<WorkSpaceLayout>(__func__); WorkSpaceLayout *layout = MEM_cnew<WorkSpaceLayout>(__func__);
BLI_assert(!workspaces_is_screen_used(bmain, screen)); BLI_assert(!workspaces_is_screen_used(bmain, screen));
#ifndef DEBUG #ifdef NDEBUG
UNUSED_VARS(bmain); UNUSED_VARS(bmain);
#endif #endif
layout->screen = screen; layout->screen = screen;

View File

@ -567,7 +567,7 @@ static const AVCodec *get_av1_encoder(
break; break;
} }
if (context->ffmpeg_crf >= 0) { if (context->ffmpeg_crf >= 0) {
/* `libsvtav1` does not support `crf` until FFmpeg builds since 2022-02-24, /* `libsvtav1` does not support CRF until FFMPEG builds since 2022-02-24,
* use `qp` as fallback. */ * use `qp` as fallback. */
ffmpeg_dict_set_int(opts, "qp", context->ffmpeg_crf); ffmpeg_dict_set_int(opts, "qp", context->ffmpeg_crf);
} }
@ -762,9 +762,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
} }
else if (context->ffmpeg_crf >= 0) { else if (context->ffmpeg_crf >= 0) {
/* As per https://trac.ffmpeg.org/wiki/Encode/VP9 we must set the bit rate to zero when /* As per https://trac.ffmpeg.org/wiki/Encode/VP9 we must set the bit rate to zero when
* encoding with vp9 in crf mode. * encoding with VP9 in CRF mode.
* Set this to always be zero for other codecs as well. * Set this to always be zero for other codecs as well.
* We don't care about bit rate in crf mode. */ * We don't care about bit rate in CRF mode. */
c->bit_rate = 0; c->bit_rate = 0;
ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf); ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
} }
@ -776,11 +776,11 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
} }
if (context->ffmpeg_preset) { if (context->ffmpeg_preset) {
/* 'preset' is used by h.264, 'deadline' is used by webm/vp9. I'm not /* 'preset' is used by h.264, 'deadline' is used by WEBM/VP9. I'm not
* setting those properties conditionally based on the video codec, * setting those properties conditionally based on the video codec,
* as the FFmpeg encoder simply ignores unknown settings anyway. */ * as the FFmpeg encoder simply ignores unknown settings anyway. */
char const *preset_name = nullptr; /* used by h.264 */ char const *preset_name = nullptr; /* Used by h.264. */
char const *deadline_name = nullptr; /* used by webm/vp9 */ char const *deadline_name = nullptr; /* Used by WEBM/VP9. */
switch (context->ffmpeg_preset) { switch (context->ffmpeg_preset) {
case FFM_PRESET_GOOD: case FFM_PRESET_GOOD:
preset_name = "medium"; preset_name = "medium";
@ -818,7 +818,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
} }
if (context->ffmpeg_type == FFMPEG_XVID) { if (context->ffmpeg_type == FFMPEG_XVID) {
/* arghhhh ... */ /* Alas! */
c->pix_fmt = AV_PIX_FMT_YUV420P; c->pix_fmt = AV_PIX_FMT_YUV420P;
c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X'); c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
} }
@ -903,7 +903,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
} }
av_dict_free(&opts); av_dict_free(&opts);
/* FFmpeg expects its data in the output pixel format. */ /* FFMPEG expects its data in the output pixel format. */
context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height); context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
if (c->pix_fmt == AV_PIX_FMT_RGBA) { if (c->pix_fmt == AV_PIX_FMT_RGBA) {
@ -1003,8 +1003,8 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
if (codec->sample_fmts) { if (codec->sample_fmts) {
/* Check if the preferred sample format for this codec is supported. /* Check if the preferred sample format for this codec is supported.
* this is because, depending on the version of libav, * this is because, depending on the version of LIBAV,
* and with the whole ffmpeg/libav fork situation, * and with the whole FFMPEG/LIBAV fork situation,
* you have various implementations around. * you have various implementations around.
* Float samples in particular are not always supported. */ * Float samples in particular are not always supported. */
const enum AVSampleFormat *p = codec->sample_fmts; const enum AVSampleFormat *p = codec->sample_fmts;
@ -1051,14 +1051,14 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
} }
/* Need to prevent floating point exception when using VORBIS audio codec, /* Need to prevent floating point exception when using VORBIS audio codec,
* initialize this value in the same way as it's done in FFmpeg itself (sergey) */ * initialize this value in the same way as it's done in FFMPEG itself (sergey) */
c->time_base.num = 1; c->time_base.num = 1;
c->time_base.den = c->sample_rate; c->time_base.den = c->sample_rate;
if (c->frame_size == 0) { if (c->frame_size == 0) {
/* Used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD)) /* Used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
* not sure if that is needed anymore, so let's try out if there are any * not sure if that is needed anymore, so let's try out if there are any
* complaints regarding some FFmpeg versions users might have. */ * complaints regarding some FFMPEG versions users might have. */
context->audio_input_samples = AV_INPUT_BUFFER_MIN_SIZE * 8 / c->bits_per_coded_sample / context->audio_input_samples = AV_INPUT_BUFFER_MIN_SIZE * 8 / c->bits_per_coded_sample /
num_channels; num_channels;
} }
@ -1134,7 +1134,7 @@ static int start_ffmpeg_impl(FFMpegContext *context,
/* Determine the correct filename */ /* Determine the correct filename */
ffmpeg_filepath_get(context, filepath, rd, context->ffmpeg_preview, suffix); ffmpeg_filepath_get(context, filepath, rd, context->ffmpeg_preview, suffix);
PRINT( PRINT(
"Starting output to %s(ffmpeg)...\n" "Starting output to %s(FFMPEG)...\n"
" Using type=%d, codec=%d, audio_codec=%d,\n" " Using type=%d, codec=%d, audio_codec=%d,\n"
" video_bitrate=%d, audio_bitrate=%d,\n" " video_bitrate=%d, audio_bitrate=%d,\n"
" gop_size=%d, autosplit=%d\n" " gop_size=%d, autosplit=%d\n"
@ -1165,7 +1165,7 @@ static int start_ffmpeg_impl(FFMpegContext *context,
of = avformat_alloc_context(); of = avformat_alloc_context();
if (!of) { if (!of) {
BKE_report(reports, RPT_ERROR, "Can't allocate ffmpeg format context"); BKE_report(reports, RPT_ERROR, "Can't allocate FFMPEG format context");
return 0; return 0;
} }
@ -1236,7 +1236,7 @@ static int start_ffmpeg_impl(FFMpegContext *context,
if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE &&
rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2)
{ {
BKE_report(reports, RPT_ERROR, "FFmpeg only supports 48khz / stereo audio for DV!"); BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
goto fail; goto fail;
} }
} }
@ -1571,7 +1571,7 @@ int BKE_ffmpeg_append(void *context_v,
static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{ {
PRINT("Closing ffmpeg...\n"); PRINT("Closing FFMPEG...\n");
# ifdef WITH_AUDASPACE # ifdef WITH_AUDASPACE
if (is_autosplit == false) { if (is_autosplit == false) {
@ -1825,9 +1825,9 @@ bool BKE_ffmpeg_alpha_channel_is_supported(const RenderData *rd)
void *BKE_ffmpeg_context_create() void *BKE_ffmpeg_context_create()
{ {
/* new ffmpeg data struct */ /* New FFMPEG data struct. */
FFMpegContext *context = static_cast<FFMpegContext *>( FFMpegContext *context = static_cast<FFMpegContext *>(
MEM_callocN(sizeof(FFMpegContext), "new ffmpeg context")); MEM_callocN(sizeof(FFMpegContext), "new FFMPEG context"));
context->ffmpeg_codec = AV_CODEC_ID_MPEG4; context->ffmpeg_codec = AV_CODEC_ID_MPEG4;
context->ffmpeg_audio_codec = AV_CODEC_ID_NONE; context->ffmpeg_audio_codec = AV_CODEC_ID_NONE;

View File

@ -269,4 +269,15 @@ template<typename T> inline void fill_index_range(MutableSpan<T> span, const T s
std::iota(span.begin(), span.end(), start); std::iota(span.begin(), span.end(), start);
} }
template<typename T>
bool indexed_data_equal(const Span<T> all_values, const Span<int> indices, const Span<T> values)
{
for (const int i : indices.index_range()) {
if (all_values[indices[i]] != values[i]) {
return true;
}
}
return false;
}
} // namespace blender::array_utils } // namespace blender::array_utils

View File

@ -190,6 +190,11 @@ inline void foreach_1_index_expr(ExprFn &&expr,
expr, handle, to_best_bit_span(first_arg), to_best_bit_span(args)...); expr, handle, to_best_bit_span(first_arg), to_best_bit_span(args)...);
} }
template<typename BitSpanT> inline void invert(const BitSpanT &data)
{
mix_into_first_expr([](const BitInt x) { return ~x; }, data);
}
template<typename FirstBitSpanT, typename... BitSpanT> template<typename FirstBitSpanT, typename... BitSpanT>
inline void inplace_or(FirstBitSpanT &first_arg, const BitSpanT &...args) inline void inplace_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
{ {

View File

@ -37,7 +37,7 @@ namespace enumerable_thread_specific_utils {
inline std::atomic<int> next_id = 0; inline std::atomic<int> next_id = 0;
inline thread_local int thread_id = next_id.fetch_add(1, std::memory_order_relaxed); inline thread_local int thread_id = next_id.fetch_add(1, std::memory_order_relaxed);
} // namespace enumerable_thread_specific_utils } // namespace enumerable_thread_specific_utils
#endif #endif /* !WITH_TBB */
/** /**
* This is mainly a wrapper for `tbb::enumerable_thread_specific`. The wrapper is needed because we * This is mainly a wrapper for `tbb::enumerable_thread_specific`. The wrapper is needed because we

View File

@ -49,7 +49,7 @@ void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src) ATTR_NONNULL(1, 2);
/** /**
* Clear for reuse, avoids re-allocation when an arena may * Clear for reuse, avoids re-allocation when an arena may
* otherwise be free'd and recreated. * otherwise be freed and recreated.
*/ */
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1); void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1);

View File

@ -2,7 +2,7 @@
* *
* SPDX-License-Identifier: GPL-2.0-or-later */ * SPDX-License-Identifier: GPL-2.0-or-later */
/* Use a define instead of `#pragma once` because of `bmesh_iterators_inline.h` */ /* Use a define instead of `#pragma once` because of `bmesh_iterators_inline.hh` */
#ifndef __BLI_TASK_H__ #ifndef __BLI_TASK_H__
#define __BLI_TASK_H__ #define __BLI_TASK_H__

View File

@ -12,7 +12,7 @@
*/ */
/* only validate array-bounds in debug mode */ /* only validate array-bounds in debug mode */
#ifdef DEBUG #ifndef NDEBUG
# define STACK_DECLARE(stack) unsigned int _##stack##_index, _##stack##_num_alloc # define STACK_DECLARE(stack) unsigned int _##stack##_index, _##stack##_num_alloc
# define STACK_INIT(stack, stack_num) \ # define STACK_INIT(stack, stack_num) \
((void)stack, \ ((void)stack, \

View File

@ -49,7 +49,7 @@
/* Setting zero so we can catch bugs in BLI_task/KDOPBVH. /* Setting zero so we can catch bugs in BLI_task/KDOPBVH.
* TODO(sergey): Deduplicate the limits with PBVH from BKE. * TODO(sergey): Deduplicate the limits with PBVH from BKE.
*/ */
#ifdef DEBUG #ifndef NDEBUG
# define KDOPBVH_THREAD_LEAF_THRESHOLD 0 # define KDOPBVH_THREAD_LEAF_THRESHOLD 0
#else #else
# define KDOPBVH_THREAD_LEAF_THRESHOLD 1024 # define KDOPBVH_THREAD_LEAF_THRESHOLD 1024

View File

@ -528,7 +528,7 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
pool->totalloc = pool->pchunk; pool->totalloc = pool->pchunk;
#endif #endif
/* Temp alloc so valgrind doesn't complain when setting free'd blocks 'next'. */ /* Temporary allocation so VALGRIND doesn't complain when setting freed blocks 'next'. */
#ifdef WITH_MEM_VALGRIND #ifdef WITH_MEM_VALGRIND
VALGRIND_MEMPOOL_ALLOC(pool, CHUNK_DATA(first), pool->csize); VALGRIND_MEMPOOL_ALLOC(pool, CHUNK_DATA(first), pool->csize);
#endif #endif

View File

@ -1159,7 +1159,8 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
/* Warning, from now on don't use len(data) since we want to ignore chunks already matched. */ /* Warning, from now on don't use len(data) since we want to ignore chunks already matched. */
size_t data_len = data_len_original; size_t data_len = data_len_original;
#define data_len_original invalid_usage #define data_len_original invalid_usage
#ifdef data_len_original /* Quiet warning. */ #ifdef data_len_original
/* Quiet warning. */
#endif #endif
const BChunkRef *chunk_list_reference_last = NULL; const BChunkRef *chunk_list_reference_last = NULL;

View File

@ -454,7 +454,7 @@ int BLI_rename(const char *from, const char *to)
* Since this functionality isn't required at the moment, leave this as-is. * Since this functionality isn't required at the moment, leave this as-is.
* Noting it as a potential improvement. */ * Noting it as a potential improvement. */
/* NOTE: To avoid the concurrency 'time of check/time of use' (TOC/TOU) issue, this code attemps /* NOTE: To avoid the concurrency 'time of check/time of use' (TOC/TOU) issue, this code attempts
* to use available solutions for an 'atomic' (file-system wise) rename operation, instead of * to use available solutions for an 'atomic' (file-system wise) rename operation, instead of
* first checking for an existing `to` target path, and then doing the rename operation if it * first checking for an existing `to` target path, and then doing the rename operation if it
* does not exists at the time of check. * does not exists at the time of check.
@ -476,9 +476,11 @@ int BLI_rename(const char *from, const char *to)
return urename(from, to, false); return urename(from, to, false);
#elif defined(__APPLE__) #elif defined(__APPLE__)
return renamex_np(from, to, RENAME_EXCL); return renamex_np(from, to, RENAME_EXCL);
#elif defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 28) #elif defined(__GLIBC_PREREQ)
# if __GLIBC_PREREQ(2, 28)
/* Most common Linux cases. */ /* Most common Linux cases. */
return renameat2(AT_FDCWD, from, AT_FDCWD, to, RENAME_NOREPLACE); return renameat2(AT_FDCWD, from, AT_FDCWD, to, RENAME_NOREPLACE);
# endif
#else #else
/* At least all BSD's currently. */ /* At least all BSD's currently. */
if (BLI_exists(to)) { if (BLI_exists(to)) {

View File

@ -22,7 +22,7 @@ namespace blender::index_mask {
template<typename T> void build_reverse_map(const IndexMask &mask, MutableSpan<T> r_map) template<typename T> void build_reverse_map(const IndexMask &mask, MutableSpan<T> r_map)
{ {
#ifdef DEBUG #ifndef NDEBUG
/* Catch errors with asserts in debug builds. */ /* Catch errors with asserts in debug builds. */
r_map.fill(-1); r_map.fill(-1);
#endif #endif

View File

@ -37,7 +37,7 @@ struct KDTree {
uint nodes_len; uint nodes_len;
uint root; uint root;
int max_node_index; int max_node_index;
#ifdef DEBUG #ifndef NDEBUG
bool is_balanced; /* ensure we call balance first */ bool is_balanced; /* ensure we call balance first */
uint nodes_len_capacity; /* max size of the tree */ uint nodes_len_capacity; /* max size of the tree */
#endif #endif
@ -97,7 +97,7 @@ KDTree *BLI_kdtree_nd_(new)(uint nodes_len_capacity)
tree->root = KD_NODE_ROOT_IS_INIT; tree->root = KD_NODE_ROOT_IS_INIT;
tree->max_node_index = -1; tree->max_node_index = -1;
#ifdef DEBUG #ifndef NDEBUG
tree->is_balanced = false; tree->is_balanced = false;
tree->nodes_len_capacity = nodes_len_capacity; tree->nodes_len_capacity = nodes_len_capacity;
#endif #endif
@ -120,7 +120,7 @@ void BLI_kdtree_nd_(insert)(KDTree *tree, int index, const float co[KD_DIMS])
{ {
KDTreeNode *node = &tree->nodes[tree->nodes_len++]; KDTreeNode *node = &tree->nodes[tree->nodes_len++];
#ifdef DEBUG #ifndef NDEBUG
BLI_assert(tree->nodes_len <= tree->nodes_len_capacity); BLI_assert(tree->nodes_len <= tree->nodes_len_capacity);
#endif #endif
@ -133,7 +133,7 @@ void BLI_kdtree_nd_(insert)(KDTree *tree, int index, const float co[KD_DIMS])
node->d = 0; node->d = 0;
tree->max_node_index = MAX2(tree->max_node_index, index); tree->max_node_index = MAX2(tree->max_node_index, index);
#ifdef DEBUG #ifndef NDEBUG
tree->is_balanced = false; tree->is_balanced = false;
#endif #endif
} }
@ -205,7 +205,7 @@ void BLI_kdtree_nd_(balance)(KDTree *tree)
tree->root = kdtree_balance(tree->nodes, tree->nodes_len, 0, 0); tree->root = kdtree_balance(tree->nodes, tree->nodes_len, 0, 0);
#ifdef DEBUG #ifndef NDEBUG
tree->is_balanced = true; tree->is_balanced = true;
#endif #endif
} }
@ -236,7 +236,7 @@ int BLI_kdtree_nd_(find_nearest)(const KDTree *tree,
float min_dist, cur_dist; float min_dist, cur_dist;
uint stack_len_capacity, cur = 0; uint stack_len_capacity, cur = 0;
#ifdef DEBUG #ifndef NDEBUG
BLI_assert(tree->is_balanced == true); BLI_assert(tree->is_balanced == true);
#endif #endif
@ -346,7 +346,7 @@ int BLI_kdtree_nd_(find_nearest_cb)(
float min_dist = FLT_MAX, cur_dist; float min_dist = FLT_MAX, cur_dist;
uint stack_len_capacity, cur = 0; uint stack_len_capacity, cur = 0;
#ifdef DEBUG #ifndef NDEBUG
BLI_assert(tree->is_balanced == true); BLI_assert(tree->is_balanced == true);
#endif #endif
@ -487,7 +487,7 @@ int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
uint stack_len_capacity, cur = 0; uint stack_len_capacity, cur = 0;
uint i, nearest_len = 0; uint i, nearest_len = 0;
#ifdef DEBUG #ifndef NDEBUG
BLI_assert(tree->is_balanced == true); BLI_assert(tree->is_balanced == true);
#endif #endif
@ -652,7 +652,7 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
uint stack_len_capacity, cur = 0; uint stack_len_capacity, cur = 0;
uint nearest_len = 0, nearest_len_capacity = 0; uint nearest_len = 0, nearest_len_capacity = 0;
#ifdef DEBUG #ifndef NDEBUG
BLI_assert(tree->is_balanced == true); BLI_assert(tree->is_balanced == true);
#endif #endif
@ -746,7 +746,7 @@ void BLI_kdtree_nd_(range_search_cb)(
float range_sq = range * range, dist_sq; float range_sq = range * range, dist_sq;
uint stack_len_capacity, cur = 0; uint stack_len_capacity, cur = 0;
#ifdef DEBUG #ifndef NDEBUG
BLI_assert(tree->is_balanced == true); BLI_assert(tree->is_balanced == true);
#endif #endif
@ -978,7 +978,7 @@ static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p)
*/ */
int BLI_kdtree_nd_(deduplicate)(KDTree *tree) int BLI_kdtree_nd_(deduplicate)(KDTree *tree)
{ {
#ifdef DEBUG #ifndef NDEBUG
tree->is_balanced = false; tree->is_balanced = false;
#endif #endif
qsort(tree->nodes, (size_t)tree->nodes_len, sizeof(*tree->nodes), kdtree_node_cmp_deduplicate); qsort(tree->nodes, (size_t)tree->nodes_len, sizeof(*tree->nodes), kdtree_node_cmp_deduplicate);

View File

@ -489,7 +489,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c
} }
} }
#endif /* __MATH_COLOR_INLINE_C__ */ #endif /* !__MATH_COLOR_INLINE_C__ */
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -3589,7 +3589,7 @@ static bool barycentric_weights(const float v1[3],
wtot = w[0] + w[1] + w[2]; wtot = w[0] + w[1] + w[2];
#ifdef DEBUG /* Avoid floating point exception when debugging. */ #ifndef NDEBUG /* Avoid floating point exception when debugging. */
if (wtot != 0.0f) if (wtot != 0.0f)
#endif #endif
{ {
@ -3686,7 +3686,7 @@ bool barycentric_coords_v2(
const float x3 = v3[0], y3 = v3[1]; const float x3 = v3[0], y3 = v3[1];
const float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3); const float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3);
#ifdef DEBUG /* Avoid floating point exception when debugging. */ #ifndef NDEBUG /* Avoid floating point exception when debugging. */
if (det != 0.0f) if (det != 0.0f)
#endif #endif
{ {
@ -3711,7 +3711,7 @@ void barycentric_weights_v2(
w[2] = cross_tri_v2(v1, v2, co); w[2] = cross_tri_v2(v1, v2, co);
wtot = w[0] + w[1] + w[2]; wtot = w[0] + w[1] + w[2];
#ifdef DEBUG /* Avoid floating point exception when debugging. */ #ifndef NDEBUG /* Avoid floating point exception when debugging. */
if (wtot != 0.0f) if (wtot != 0.0f)
#endif #endif
{ {
@ -3734,7 +3734,7 @@ void barycentric_weights_v2_clamped(
w[2] = max_ff(cross_tri_v2(v1, v2, co), 0.0f); w[2] = max_ff(cross_tri_v2(v1, v2, co), 0.0f);
wtot = w[0] + w[1] + w[2]; wtot = w[0] + w[1] + w[2];
#ifdef DEBUG /* Avoid floating point exception when debugging. */ #ifndef NDEBUG /* Avoid floating point exception when debugging. */
if (wtot != 0.0f) if (wtot != 0.0f)
#endif #endif
{ {
@ -3757,7 +3757,7 @@ void barycentric_weights_v2_persp(
w[2] = cross_tri_v2(v1, v2, co) / v3[3]; w[2] = cross_tri_v2(v1, v2, co) / v3[3];
wtot = w[0] + w[1] + w[2]; wtot = w[0] + w[1] + w[2];
#ifdef DEBUG /* Avoid floating point exception when debugging. */ #ifndef NDEBUG /* Avoid floating point exception when debugging. */
if (wtot != 0.0f) if (wtot != 0.0f)
#endif #endif
{ {
@ -3849,7 +3849,7 @@ void barycentric_weights_v2_quad(const float v1[2],
wtot = w[0] + w[1] + w[2] + w[3]; wtot = w[0] + w[1] + w[2] + w[3];
#ifdef DEBUG /* Avoid floating point exception when debugging. */ #ifndef NDEBUG /* Avoid floating point exception when debugging. */
if (wtot != 0.0f) if (wtot != 0.0f)
#endif #endif
{ {

View File

@ -17,7 +17,7 @@
/******************************** Quaternions ********************************/ /******************************** Quaternions ********************************/
/* used to test is a quat is not normalized (only used for debug prints) */ /* used to test is a quat is not normalized (only used for debug prints) */
#ifdef DEBUG #ifndef NDEBUG
# define QUAT_EPSILON 0.0001 # define QUAT_EPSILON 0.0001
#endif #endif
@ -216,7 +216,7 @@ static void quat_to_mat3_no_error(float m[3][3], const float q[4])
void quat_to_mat3(float m[3][3], const float q[4]) void quat_to_mat3(float m[3][3], const float q[4])
{ {
#ifdef DEBUG #ifndef NDEBUG
float f; float f;
if (!((f = dot_qtqt(q, q)) == 0.0f || (fabsf(f - 1.0f) < (float)QUAT_EPSILON))) { if (!((f = dot_qtqt(q, q)) == 0.0f || (fabsf(f - 1.0f) < (float)QUAT_EPSILON))) {
fprintf(stderr, fprintf(stderr,
@ -232,7 +232,7 @@ void quat_to_mat4(float m[4][4], const float q[4])
{ {
double q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc; double q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
#ifdef DEBUG #ifndef NDEBUG
if (!((q0 = dot_qtqt(q, q)) == 0.0 || (fabs(q0 - 1.0) < QUAT_EPSILON))) { if (!((q0 = dot_qtqt(q, q)) == 0.0 || (fabs(q0 - 1.0) < QUAT_EPSILON))) {
fprintf(stderr, fprintf(stderr,
"Warning! quat_to_mat4() called with non-normalized: size %.8f *** report a bug ***\n", "Warning! quat_to_mat4() called with non-normalized: size %.8f *** report a bug ***\n",
@ -1065,7 +1065,7 @@ void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
{ {
float ha, si; float ha, si;
#ifdef DEBUG #ifndef NDEBUG
if (!((ha = dot_qtqt(q, q)) == 0.0f || (fabsf(ha - 1.0f) < (float)QUAT_EPSILON))) { if (!((ha = dot_qtqt(q, q)) == 0.0f || (fabsf(ha - 1.0f) < (float)QUAT_EPSILON))) {
fprintf(stderr, fprintf(stderr,
"Warning! quat_to_axis_angle() called with non-normalized: size %.8f *** report a bug " "Warning! quat_to_axis_angle() called with non-normalized: size %.8f *** report a bug "

View File

@ -455,7 +455,7 @@ static void pf_coord_remove(PolyFill *pf, PolyIndex *pi)
if (pf->kdtree.node_num) { if (pf->kdtree.node_num) {
kdtree2d_node_remove(&pf->kdtree, pi->index); kdtree2d_node_remove(&pf->kdtree, pi->index);
} }
#endif #endif /* USE_KDTREE */
pi->next->prev = pi->prev; pi->next->prev = pi->prev;
pi->prev->next = pi->next; pi->prev->next = pi->next;
@ -463,10 +463,10 @@ static void pf_coord_remove(PolyFill *pf, PolyIndex *pi)
if (UNLIKELY(pf->indices == pi)) { if (UNLIKELY(pf->indices == pi)) {
pf->indices = pi->next; pf->indices = pi->next;
} }
#ifdef DEBUG #ifndef NDEBUG
pi->index = (uint32_t)-1; pi->index = (uint32_t)-1;
pi->next = pi->prev = NULL; pi->next = pi->prev = NULL;
#endif #endif /* !NDEBUG */
pf->coords_num -= 1; pf->coords_num -= 1;
} }

View File

@ -842,7 +842,7 @@ uint BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float n
BLI_assert(!nor_proj || len_squared_v3(nor_proj) > FLT_EPSILON); BLI_assert(!nor_proj || len_squared_v3(nor_proj) > FLT_EPSILON);
#ifdef DEBUG #ifndef NDEBUG
for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) { for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
/* these values used to be set, /* these values used to be set,
* however they should always be zero'd so check instead */ * however they should always be zero'd so check instead */
@ -984,7 +984,7 @@ uint BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float n
} }
if (eed) { if (eed) {
/* otherwise it's impossible to be sure you can clear vertices */ /* otherwise it's impossible to be sure you can clear vertices */
#ifdef DEBUG #ifndef NDEBUG
printf("No vertices with 250 edges allowed!\n"); printf("No vertices with 250 edges allowed!\n");
#endif #endif
return 0; return 0;
@ -1027,7 +1027,7 @@ uint BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float n
eed->v1->edge_count++; eed->v1->edge_count++;
eed->v2->edge_count++; eed->v2->edge_count++;
} }
#ifdef DEBUG #ifndef NDEBUG
/* ensure we're right! */ /* ensure we're right! */
for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) { for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
BLI_assert(eed->v1->edge_count != 1); BLI_assert(eed->v1->edge_count != 1);

View File

@ -125,7 +125,7 @@ TEST_F(FileOpsTest, rename)
ASSERT_TRUE(BLI_exists(test_dirpath_src.c_str())); ASSERT_TRUE(BLI_exists(test_dirpath_src.c_str()));
ASSERT_TRUE(BLI_exists(test_dirpath_dst.c_str())); ASSERT_TRUE(BLI_exists(test_dirpath_dst.c_str()));
/* `test_dirpath_dst` now exists, but is empty, so overwrite rename should suceed. */ /* `test_dirpath_dst` now exists, but is empty, so overwrite rename should succeed. */
ASSERT_EQ(0, BLI_rename_overwrite(test_dirpath_src.c_str(), test_dirpath_dst.c_str())); ASSERT_EQ(0, BLI_rename_overwrite(test_dirpath_src.c_str(), test_dirpath_dst.c_str()));
ASSERT_FALSE(BLI_exists(test_dirpath_src.c_str())); ASSERT_FALSE(BLI_exists(test_dirpath_src.c_str()));
ASSERT_TRUE(BLI_exists(test_dirpath_dst.c_str())); ASSERT_TRUE(BLI_exists(test_dirpath_dst.c_str()));

View File

@ -99,7 +99,6 @@
#include "BLO_readfile.h" #include "BLO_readfile.h"
#include "BLO_undofile.hh" #include "BLO_undofile.hh"
#include "SEQ_clipboard.hh"
#include "SEQ_iterator.hh" #include "SEQ_iterator.hh"
#include "SEQ_modifier.hh" #include "SEQ_modifier.hh"
#include "SEQ_sequencer.hh" #include "SEQ_sequencer.hh"

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