Mesh: Replace auto smooth with node group #108014

Merged
Hans Goudey merged 149 commits from HooglyBoogly/blender:refactor-mesh-corner-normals-lazy into main 2023-10-20 16:54:20 +02:00
178 changed files with 1723 additions and 930 deletions
Showing only changes of commit dd6af6ff6b - Show all commits

View File

@ -511,7 +511,7 @@ Boost uses ICU library (required for linking with static Boost built with libicu
endif()
# Misc
if(WIN32 OR APPLE)
if(WIN32 OR APPLE OR ((UNIX AND (NOT HAIKU)) AND WITH_GHOST_WAYLAND))
option(WITH_INPUT_IME "Enable Input Method Editor (IME) for complex Asian character input" ON)
else()
set(WITH_INPUT_IME OFF)
@ -846,6 +846,12 @@ Build and link against address sanitizer (only for Debug & RelWithDebInfo target
OFF
)
mark_as_advanced(WITH_COMPILER_ASAN)
option(WITH_COMPILER_ASAN_EXTERN "\
Build `extern` dependencies with address sanitizer when WITH_COMPILER_ASAN is on. \
Can cause linking issues due to too large binary size."
OFF
)
mark_as_advanced(WITH_EXTERN_ASAN)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
if(WITH_COMPILER_ASAN)

View File

@ -20,6 +20,14 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
)
endif()
if(WITH_COMPILER_ASAN AND NOT WITH_COMPILER_ASAN_EXTERN)
# Disable ASAN for extern dependencies, as it can lead to linking issues due to too large binaries.
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -fno-sanitize=all")
string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " -fno-sanitize=all")
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-sanitize=all")
string(APPEND CMAKE_C_FLAGS_DEBUG " -fno-sanitize=all")
endif()
add_subdirectory(rangetree)
add_subdirectory(nanosvg)

View File

@ -226,4 +226,13 @@ ccl_device_inline Spectrum bsdf_principled_hair_sigma_from_concentration(const f
pheomelanin * rgb_to_spectrum(pheomelanin_color);
}
/* Computes the weight for base closure(s) which are layered under another closure.
* layer_albedo is an estimate of the top layer's reflectivity, while weight is the closure weight
* of the entire base+top combination. */
ccl_device_inline Spectrum closure_layering_weight(const Spectrum layer_albedo,
const Spectrum weight)
{
return weight * saturatef(1.0f - reduce_max(safe_divide_color(layer_albedo, weight)));
}
CCL_NAMESPACE_END

View File

@ -151,7 +151,7 @@ ccl_device void flatten_closure_tree(KernelGlobals kg,
if (stack_size == layer_stack_level) {
/* We just finished processing the top layers of a Layer closure, so adjust the weight to
* account for the layering. */
weight *= saturatef(1.0f - reduce_max(safe_divide_color(layer_albedo, weight)));
weight = closure_layering_weight(layer_albedo, weight);
layer_stack_level = -1;
/* If it's fully occluded, skip the base layer we just popped from the stack and grab
* the next entry instead. */

View File

@ -204,7 +204,7 @@ ccl_device
/* Attenuate lower layers */
Spectrum albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
weight *= 1.0f - reduce_max(safe_divide_color(albedo, weight));
weight = closure_layering_weight(albedo, weight);
}
}
}
@ -229,7 +229,7 @@ ccl_device
/* Attenuate lower layers */
Spectrum albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
weight *= 1.0f - reduce_max(safe_divide_color(albedo, weight));
weight = closure_layering_weight(albedo, weight);
}
}
@ -367,7 +367,7 @@ ccl_device
/* Attenuate lower layers */
Spectrum albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
weight *= 1.0f - reduce_max(safe_divide_color(albedo, weight));
weight = closure_layering_weight(albedo, weight);
}
}

View File

@ -75,6 +75,10 @@ set(LIB
PRIVATE bf::dna
)
if(WITH_INPUT_IME)
add_definitions(-DWITH_INPUT_IME)
endif()
if(WITH_OPENGL_BACKEND)
list(APPEND INC_SYS
${Epoxy_INCLUDE_DIRS}
@ -177,9 +181,6 @@ elseif(WITH_GHOST_SDL)
endif()
elseif(APPLE AND NOT WITH_GHOST_X11)
if(WITH_INPUT_IME)
add_definitions(-DWITH_INPUT_IME)
endif()
list(APPEND SRC
intern/GHOST_DisplayManagerCocoa.mm
intern/GHOST_SystemCocoa.mm
@ -439,6 +440,11 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/unstable/primary-selection/primary-selection-unstable-v1.xml"
)
if(WITH_INPUT_IME)
generate_protocol_bindings(
"${WAYLAND_PROTOCOLS_DIR}/unstable/text-input/text-input-unstable-v3.xml"
)
endif()
unset(INC_DST)
@ -498,8 +504,6 @@ elseif(WIN32)
)
if(WITH_INPUT_IME)
add_definitions(-DWITH_INPUT_IME)
list(APPEND SRC
intern/GHOST_ImeWin32.cc

View File

@ -119,6 +119,10 @@ typedef enum {
* Support for sampling a color outside of the Blender windows.
*/
GHOST_kCapabilityDesktopSample = (1 << 5),
/**
* Supports IME text input methods (when `WITH_INPUT_IME` is defined).
*/
GHOST_kCapabilityInputIME = (1 << 6),
} GHOST_TCapabilityFlag;
/**
@ -128,7 +132,7 @@ typedef enum {
#define GHOST_CAPABILITY_FLAG_ALL \
(GHOST_kCapabilityCursorWarp | GHOST_kCapabilityWindowPosition | \
GHOST_kCapabilityPrimaryClipboard | GHOST_kCapabilityGPUReadFrontBuffer | \
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample)
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample | GHOST_kCapabilityInputIME)
/* Xtilt and Ytilt represent how much the pen is tilted away from
* vertically upright in either the X or Y direction, with X and Y the

View File

@ -51,7 +51,7 @@ class GHOST_SystemHeadless : public GHOST_System {
~(GHOST_kCapabilityWindowPosition | GHOST_kCapabilityCursorWarp |
GHOST_kCapabilityPrimaryClipboard |
GHOST_kCapabilityDesktopSample |
GHOST_kCapabilityClipboardImages));
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityInputIME));
}
char *getClipboard(bool /*selection*/) const override
{

View File

@ -781,7 +781,9 @@ GHOST_TCapabilityFlag GHOST_SystemSDL::getCapabilities() const
/* This SDL back-end has not yet implemented color sampling the desktop. */
GHOST_kCapabilityDesktopSample |
/* This SDL back-end has not yet implemented image copy/paste. */
GHOST_kCapabilityClipboardImages));
GHOST_kCapabilityClipboardImages |
/* No support yet for IME input methods. */
GHOST_kCapabilityInputIME));
}
char *GHOST_SystemSDL::getClipboard(bool /*selection*/) const

View File

@ -68,6 +68,9 @@
#include <viewporter-client-protocol.h>
#include <xdg-activation-v1-client-protocol.h>
#include <xdg-output-unstable-v1-client-protocol.h>
#ifdef WITH_INPUT_IME
# include <text-input-unstable-v3-client-protocol.h>
#endif
/* Decorations `xdg_decor`. */
#include <xdg-decoration-unstable-v1-client-protocol.h>
@ -720,6 +723,51 @@ static void gwl_primary_selection_discard_source(GWL_PrimarySelection *primary)
primary->data_source = nullptr;
}
#ifdef WITH_INPUT_IME
struct GWL_SeatIME {
struct wl_surface *surface_window = nullptr;
GHOST_TEventImeData event_ime_data = {
/*result_len*/ nullptr,
/*composite_len*/ nullptr,
/*result*/ nullptr,
/*composite*/ nullptr,
/*cursor_position*/ -1,
/*target_start*/ -1,
/*target_end*/ -1,
};
/** When true, the client has indicated that IME input should be activated on text entry. */
bool is_enabled = false;
/**
* When true, some pre-edit text has been entered
* (an IME popup may be showing however this isn't known).
*/
bool has_preedit = false;
/** Storage for #GHOST_TEventImeData::result (the result of the `commit_string` callback). */
std::string result;
/** Storage for #GHOST_TEventImeData::composite (the result of the `preedit_string` callback). */
std::string composite;
/** #zwp_text_input_v3_listener::commit_string was called with a null text argument. */
bool result_is_null = false;
/** #zwp_text_input_v3_listener::preedit_string was called with a null text argument. */
bool composite_is_null = false;
/** #zwp_text_input_v3_listener::preedit_string was called. */
bool has_preedit_string_callback = false;
/** #zwp_text_input_v3_listener::commit_string was called. */
bool has_commit_string_callback = false;
/** Bounds (use for comparison). */
struct {
int x = -1;
int y = -1;
int w = -1;
int h = -1;
} rect;
};
#endif /* WITH_INPUT_IME */
struct GWL_Seat {
/** Wayland core types. */
@ -755,6 +803,10 @@ struct GWL_Seat {
/** All currently active tablet tools (needed for changing the cursor). */
std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools;
#ifdef WITH_INPUT_IME
struct zwp_text_input_v3 *text_input = nullptr;
#endif
} wp;
/** XKB native types. */
@ -780,6 +832,10 @@ struct GWL_Seat {
} xkb;
#ifdef WITH_INPUT_IME
GWL_SeatIME ime;
#endif
GHOST_SystemWayland *system = nullptr;
std::string name;
@ -914,6 +970,60 @@ static void gwl_seat_key_repeat_timer_remove(GWL_Seat *seat)
seat->key_repeat.timer = nullptr;
}
#ifdef WITH_INPUT_IME
static void gwl_seat_ime_full_reset(GWL_Seat *seat)
{
const GWL_SeatIME ime_default{};
/* Preserve the following members since they represent the state of the connection to Wayland.
* or which callbacks have run (which shouldn't be reset). */
wl_surface *surface_window = seat->ime.surface_window;
const bool is_enabled = seat->ime.is_enabled;
const bool has_preedit_string_callback = seat->ime.has_preedit_string_callback;
const bool has_commit_string_callback = seat->ime.has_commit_string_callback;
seat->ime = ime_default;
seat->ime.surface_window = surface_window;
seat->ime.is_enabled = is_enabled;
seat->ime.has_preedit_string_callback = has_preedit_string_callback;
seat->ime.has_commit_string_callback = has_commit_string_callback;
}
static void gwl_seat_ime_result_reset(GWL_Seat *seat)
{
seat->ime.result.clear();
seat->ime.result_is_null = false;
GHOST_TEventImeData &event_ime_data = seat->ime.event_ime_data;
event_ime_data.result_len = nullptr;
event_ime_data.result = nullptr;
}
static void gwl_seat_ime_preedit_reset(GWL_Seat *seat)
{
seat->ime.composite.clear();
seat->ime.composite_is_null = false;
GHOST_TEventImeData &event_ime_data = seat->ime.event_ime_data;
event_ime_data.composite_len = nullptr;
event_ime_data.composite = nullptr;
event_ime_data.cursor_position = -1;
event_ime_data.target_start = -1;
event_ime_data.target_end = -1;
}
static void gwl_seat_ime_rect_reset(GWL_Seat *seat)
{
seat->ime.rect.x = -1;
seat->ime.rect.y = -1;
seat->ime.rect.w = -1;
seat->ime.rect.h = -1;
}
#endif /* WITH_INPUT_IME */
/** \} */
/* -------------------------------------------------------------------- */
@ -945,6 +1055,9 @@ struct GWL_Display {
wp_viewporter *viewporter = nullptr;
zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
zwp_pointer_gestures_v1 *pointer_gestures = nullptr;
#ifdef WITH_INPUT_IME
struct zwp_text_input_manager_v3 *text_input_manager = nullptr;
#endif
} wp;
/** Wayland XDG types. */
@ -4338,6 +4451,229 @@ static const zwp_primary_selection_source_v1_listener primary_selection_source_l
/** \} */
/* -------------------------------------------------------------------- */
/** \name Listener (Text Input), #zwp_text_input_manager_v3
* \{ */
#ifdef WITH_INPUT_IME
class GHOST_EventIME : public GHOST_Event {
public:
/**
* Constructor.
* \param msec: The time this event was generated.
* \param type: The type of key event.
* \param key: The key code of the key.
*/
GHOST_EventIME(uint64_t msec, GHOST_TEventType type, GHOST_IWindow *window, void *customdata)
: GHOST_Event(msec, type, window)
{
this->m_data = customdata;
}
};
static CLG_LogRef LOG_WL_TEXT_INPUT = {"ghost.wl.handle.text_input"};
# define LOG (&LOG_WL_TEXT_INPUT)
static void text_input_handle_enter(void *data,
struct zwp_text_input_v3 * /*zwp_text_input_v3*/,
struct wl_surface *surface)
{
if (!ghost_wl_surface_own(surface)) {
return;
}
CLOG_INFO(LOG, 2, "enter");
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
seat->ime.surface_window = surface;
}
static void text_input_handle_leave(void *data,
struct zwp_text_input_v3 * /*zwp_text_input_v3*/,
struct wl_surface *surface)
{
/* Can be null when closing a window. */
if (!ghost_wl_surface_own_with_null_check(surface)) {
return;
}
CLOG_INFO(LOG, 2, "leave");
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
if (seat->ime.surface_window == surface) {
seat->ime.surface_window = nullptr;
}
}
static void text_input_handle_preedit_string(void *data,
struct zwp_text_input_v3 * /*zwp_text_input_v3*/,
const char *text,
int32_t cursor_begin,
int32_t cursor_end)
{
CLOG_INFO(LOG,
2,
"preedit_string (text=\"%s\", cursor_begin=%d, cursor_end=%d)",
text ? text : "<null>",
cursor_begin,
cursor_end);
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
if (UNLIKELY(seat->ime.surface_window == nullptr)) {
return;
}
if (seat->ime.has_preedit == false) {
/* Starting IME input. */
gwl_seat_ime_full_reset(seat);
}
seat->ime.composite_is_null = (text == nullptr);
if (!seat->ime.composite_is_null) {
seat->ime.composite = text;
seat->ime.event_ime_data.composite = (void *)seat->ime.composite.c_str();
seat->ime.event_ime_data.composite_len = (void *)seat->ime.composite.size();
seat->ime.event_ime_data.cursor_position = cursor_begin;
seat->ime.event_ime_data.target_start = cursor_begin;
seat->ime.event_ime_data.target_end = cursor_end;
}
seat->ime.has_preedit_string_callback = true;
}
static void text_input_handle_commit_string(void *data,
struct zwp_text_input_v3 * /*zwp_text_input_v3*/,
const char *text)
{
CLOG_INFO(LOG, 2, "commit_string (text=\"%s\")", text ? text : "<null>");
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
if (UNLIKELY(seat->ime.surface_window == nullptr)) {
return;
}
seat->ime.result_is_null = (text == nullptr);
if (seat->ime.result_is_null) {
seat->ime.result = "";
}
else {
seat->ime.result = text;
}
seat->ime.result_is_null = (text == nullptr);
seat->ime.event_ime_data.result = (void *)seat->ime.result.c_str();
seat->ime.event_ime_data.result_len = (void *)seat->ime.result.size();
seat->ime.event_ime_data.cursor_position = seat->ime.result.size();
seat->ime.has_commit_string_callback = true;
}
static void text_input_handle_delete_surrounding_text(
void * /*data*/,
struct zwp_text_input_v3 * /*zwp_text_input_v3*/,
uint32_t before_length,
uint32_t after_length)
{
CLOG_INFO(LOG,
2,
"delete_surrounding_text (before_length=%u, after_length=%u)",
before_length,
after_length);
/* NOTE: Currently unused, do we care about this event?
* SDL ignores this event. */
}
static void text_input_handle_done(void *data,
struct zwp_text_input_v3 * /*zwp_text_input_v3*/,
uint32_t /*serial*/)
{
CLOG_INFO(LOG, 2, "done");
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
GHOST_SystemWayland *system = seat->system;
GHOST_WindowWayland *win = ghost_wl_surface_user_data(seat->ime.surface_window);
if (seat->ime.has_commit_string_callback) {
if (seat->ime.has_preedit) {
const bool is_end = seat->ime.composite_is_null;
if (is_end) {
seat->ime.has_preedit = false;
/* `commit_string` (end). */
system->pushEvent_maybe_pending(new GHOST_EventIME(system->getMilliSeconds(),
GHOST_kEventImeComposition,
win,
&seat->ime.event_ime_data));
system->pushEvent_maybe_pending(new GHOST_EventIME(system->getMilliSeconds(),
GHOST_kEventImeCompositionEnd,
win,
&seat->ime.event_ime_data));
}
else {
/* `commit_string` (continues). */
system->pushEvent_maybe_pending(new GHOST_EventIME(system->getMilliSeconds(),
GHOST_kEventImeComposition,
win,
&seat->ime.event_ime_data));
}
}
else {
/* `commit_string` ran with no active IME popup, start & end to insert text. */
system->pushEvent_maybe_pending(new GHOST_EventIME(system->getMilliSeconds(),
GHOST_kEventImeCompositionStart,
win,
&seat->ime.event_ime_data));
system->pushEvent_maybe_pending(new GHOST_EventIME(
system->getMilliSeconds(), GHOST_kEventImeComposition, win, &seat->ime.event_ime_data));
system->pushEvent_maybe_pending(new GHOST_EventIME(system->getMilliSeconds(),
GHOST_kEventImeCompositionEnd,
win,
&seat->ime.event_ime_data));
}
if (seat->ime.has_preedit == false) {
gwl_seat_ime_preedit_reset(seat);
}
}
else if (seat->ime.has_preedit_string_callback) {
const bool is_end = seat->ime.composite_is_null;
if (is_end) {
/* `preedit_string` (end). */
seat->ime.has_preedit = false;
system->pushEvent_maybe_pending(new GHOST_EventIME(seat->system->getMilliSeconds(),
GHOST_kEventImeCompositionEnd,
win,
&seat->ime.event_ime_data));
}
else {
const bool is_start = seat->ime.has_preedit == false;
/* `preedit_string` (start or continue). */
seat->ime.has_preedit = true;
system->pushEvent_maybe_pending(new GHOST_EventIME(
seat->system->getMilliSeconds(),
is_start ? GHOST_kEventImeCompositionStart : GHOST_kEventImeComposition,
win,
&seat->ime.event_ime_data));
}
}
seat->ime.has_preedit_string_callback = false;
seat->ime.has_commit_string_callback = false;
}
static struct zwp_text_input_v3_listener text_input_listener = {
/*enter*/ text_input_handle_enter,
/*leave*/ text_input_handle_leave,
/*preedit_string*/ text_input_handle_preedit_string,
/*commit_string*/ text_input_handle_commit_string,
/*delete_surrounding_text*/ text_input_handle_delete_surrounding_text,
/*done*/ text_input_handle_done,
};
# undef LOG
#endif /* WITH_INPUT_IME. */
/** \} */
/* -------------------------------------------------------------------- */
/** \name Listener (Seat), #wl_seat_listener
* \{ */
@ -5030,6 +5366,20 @@ static void gwl_registry_wl_seat_update(GWL_Display *display,
else {
seat->wp.primary_selection_device = nullptr;
}
#ifdef WITH_INPUT_IME
if (display->wp.text_input_manager) {
if (seat->wp.text_input == nullptr) {
seat->wp.text_input = zwp_text_input_manager_v3_get_text_input(
display->wp.text_input_manager, seat->wl.seat);
zwp_text_input_v3_set_user_data(seat->wp.text_input, seat);
zwp_text_input_v3_add_listener(seat->wp.text_input, &text_input_listener, seat);
}
}
else {
seat->wp.text_input = nullptr;
}
#endif /* WITH_INPUT_IME */
}
static void gwl_registry_wl_seat_remove(GWL_Display *display, void *user_data, const bool on_exit)
{
@ -5312,6 +5662,28 @@ static void gwl_registry_wp_primary_selection_device_manager_remove(GWL_Display
*value_p = nullptr;
}
#ifdef WITH_INPUT_IME
/* #GWL_Display.wp_text_input_manager */
static void gwl_registry_wp_text_input_manager_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->wp.text_input_manager = static_cast<zwp_text_input_manager_v3 *>(wl_registry_bind(
display->wl.registry, params->name, &zwp_text_input_manager_v3_interface, 1));
gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_text_input_manager_remove(GWL_Display *display,
void * /*user_data*/,
const bool /*on_exit*/)
{
struct zwp_text_input_manager_v3 **value_p = &display->wp.text_input_manager;
zwp_text_input_manager_v3_destroy(*value_p);
*value_p = nullptr;
}
#endif /* WITH_INPUT_IME */
/**
* Map interfaces to initialization functions.
*
@ -5379,6 +5751,14 @@ static const GWL_RegistryHandler gwl_registry_handlers[] = {
/*update_fn*/ nullptr,
/*remove_fn*/ gwl_registry_wp_relative_pointer_manager_remove,
},
#ifdef WITH_INPUT_IME
{
/*interface_p*/ &zwp_text_input_manager_v3_interface.name,
/*add_fn*/ gwl_registry_wp_text_input_manager_add,
/*update_fn*/ nullptr,
/*remove_fn*/ gwl_registry_wp_text_input_manager_remove,
},
#endif
/* Higher level interfaces. */
{
/*interface_p*/ &zwp_pointer_constraints_v1_interface.name,
@ -7143,6 +7523,105 @@ GHOST_TimerManager *GHOST_SystemWayland::ghost_timer_manager()
/** \} */
/* -------------------------------------------------------------------- */
/** \name Public WAYLAND Text Input (IME) Functions
*
* Functionality only used for the WAYLAND implementation.
* \{ */
#ifdef WITH_INPUT_IME
void GHOST_SystemWayland::ime_begin(
GHOST_WindowWayland *win, int32_t x, int32_t y, int32_t w, int32_t h, bool completed) const
{
GWL_Seat *seat = gwl_display_seat_active_get(display_);
if (UNLIKELY(!seat)) {
return;
}
if (seat->wp.text_input == nullptr) {
return;
}
/* Prevent a feedback loop because the commits from this function cause
* #zwp_text_input_v3_listener::preedit_string to run again which sends an event,
* refreshing the position, running this function again. */
gwl_seat_ime_result_reset(seat);
/* Don't re-enable if we're already enabled. */
if (seat->ime.is_enabled && completed) {
return;
}
bool force_rect_update = false;
if (seat->ime.is_enabled == false) {
seat->ime.has_preedit = false;
seat->ime.is_enabled = true;
/* NOTE(@flibit): For some reason this has to be done twice,
* it appears to be a bug in mutter? Maybe? */
zwp_text_input_v3_enable(seat->wp.text_input);
zwp_text_input_v3_commit(seat->wp.text_input);
zwp_text_input_v3_enable(seat->wp.text_input);
zwp_text_input_v3_commit(seat->wp.text_input);
/* Now that it's enabled, set the input properties. */
zwp_text_input_v3_set_content_type(seat->wp.text_input,
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL);
gwl_seat_ime_rect_reset(seat);
force_rect_update = true;
}
if ((force_rect_update == false) && /* Was just created, always update. */
(seat->ime.rect.x == x) && /* X. */
(seat->ime.rect.y == y) && /* Y. */
(seat->ime.rect.w == w) && /* W. */
(seat->ime.rect.h == h)) /* H. */
{
/* Only re-update the rectangle as needed. */
printf("DONT REPOSITION\n");
}
else {
const int rect_x = wl_fixed_to_int(win->wl_fixed_from_window(wl_fixed_from_int(x)));
const int rect_y = wl_fixed_to_int(win->wl_fixed_from_window(wl_fixed_from_int(y)));
const int rect_w = wl_fixed_to_int(win->wl_fixed_from_window(wl_fixed_from_int(w))) + 1;
const int rect_h = wl_fixed_to_int(win->wl_fixed_from_window(wl_fixed_from_int(h))) + 1;
zwp_text_input_v3_set_cursor_rectangle(seat->wp.text_input, rect_x, rect_y, rect_w, rect_h);
zwp_text_input_v3_commit(seat->wp.text_input);
seat->ime.rect.x = x;
seat->ime.rect.y = y;
seat->ime.rect.w = w;
seat->ime.rect.h = h;
}
}
void GHOST_SystemWayland::ime_end(GHOST_WindowWayland * /*window*/) const
{
GWL_Seat *seat = gwl_display_seat_active_get(display_);
if (UNLIKELY(!seat)) {
return;
}
seat->ime.is_enabled = false;
gwl_seat_ime_rect_reset(seat);
if (seat->wp.text_input == nullptr) {
return;
}
zwp_text_input_v3_disable(seat->wp.text_input);
zwp_text_input_v3_commit(seat->wp.text_input);
}
#endif /* WITH_INPUT_IME */
/** \} */
/* -------------------------------------------------------------------- */
/** \name Public WAYLAND Query Access
* \{ */
@ -7215,6 +7694,9 @@ bool GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
SURFACE_CLEAR_PTR(seat->tablet.wl.surface_window);
SURFACE_CLEAR_PTR(seat->keyboard.wl.surface_window);
SURFACE_CLEAR_PTR(seat->wl.surface_window_focus_dnd);
#ifdef WITH_INPUT_IME
SURFACE_CLEAR_PTR(seat->ime.surface_window);
#endif
}
#undef SURFACE_CLEAR_PTR

View File

@ -236,6 +236,10 @@ class GHOST_SystemWayland : public GHOST_System {
struct wl_shm *wl_shm_get() const;
void ime_begin(
GHOST_WindowWayland *win, int32_t x, int32_t y, int32_t w, int32_t h, bool completed) const;
void ime_end(GHOST_WindowWayland *win) const;
static const char *xdg_app_id_get();
/* WAYLAND utility functions. */

View File

@ -1742,7 +1742,9 @@ GHOST_TCapabilityFlag GHOST_SystemX11::getCapabilities() const
/* No support yet for desktop sampling. */
GHOST_kCapabilityDesktopSample |
/* No support yet for image copy/paste. */
GHOST_kCapabilityClipboardImages));
GHOST_kCapabilityClipboardImages |
/* No support yet for IME input methods. */
GHOST_kCapabilityInputIME));
}
void GHOST_SystemX11::addDirtyWindow(GHOST_WindowX11 *bad_wind)

View File

@ -2012,6 +2012,20 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
}
}
#ifdef WITH_INPUT_IME
void GHOST_WindowWayland::beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed)
{
system_->ime_begin(this, x, y, w, h, completed);
}
void GHOST_WindowWayland::endIME()
{
system_->ime_end(this);
}
#endif
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -140,6 +140,11 @@ class GHOST_WindowWayland : public GHOST_Window {
void setOpaque() const;
#endif
#ifdef WITH_INPUT_IME
void beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed) override;
void endIME() override;
#endif /* WITH_INPUT_IME */
/* WAYLAND direct-data access. */
int scale_get() const;

View File

@ -446,7 +446,7 @@ class NODE_PT_geometry_node_tool_object_types(Panel):
types = [
("is_type_mesh", "Mesh", 'MESH_DATA'),
("is_type_curve", "Curves", 'CURVES_DATA'),
("is_type_curve", "Hair Curves", 'CURVES_DATA'),
]
if context.preferences.experimental.use_new_point_cloud_type:
types.append(("is_type_point_cloud", "Point Cloud", 'POINTCLOUD_DATA'))

View File

@ -5,6 +5,7 @@
#pragma once
#include "DNA_curves_types.h"
#include "DNA_object_types.h" /* #BoundBox. */
/** \file
* \ingroup bke
@ -24,7 +25,7 @@ struct Scene;
void *BKE_curves_add(struct Main *bmain, const char *name);
struct BoundBox *BKE_curves_boundbox_get(struct Object *ob);
BoundBox BKE_curves_boundbox_get(struct Object *ob);
bool BKE_curves_attribute_required(const struct Curves *curves, const char *name);

View File

@ -23,6 +23,7 @@
#include "DNA_gpencil_legacy_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_object_types.h" /* #BoundBox. */
struct Main;
struct Depsgraph;
@ -801,7 +802,7 @@ inline bool GreasePencil::has_active_layer() const
void *BKE_grease_pencil_add(Main *bmain, const char *name);
GreasePencil *BKE_grease_pencil_new_nomain();
GreasePencil *BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_src);
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob);
BoundBox BKE_grease_pencil_boundbox_get(Object *ob);
void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *object);
void BKE_grease_pencil_duplicate_drawing_array(const GreasePencil *grease_pencil_src,
GreasePencil *grease_pencil_dst);
@ -826,6 +827,7 @@ Material *BKE_grease_pencil_object_material_ensure_from_active_input_brush(Main
Brush *brush);
Material *BKE_grease_pencil_object_material_ensure_from_active_input_material(Object *ob);
Material *BKE_grease_pencil_object_material_ensure_active(Object *ob);
void BKE_grease_pencil_material_remap(GreasePencil *grease_pencil, const uint *remap, int totcol);
bool BKE_grease_pencil_references_cyclic_check(const GreasePencil *id_reference,
const GreasePencil *grease_pencil);

View File

@ -89,19 +89,19 @@ class Instances {
* Contains the data that is used by the individual instances.
* Actual instances store an index ("handle") into this vector.
*/
blender::Vector<InstanceReference> references_;
Vector<InstanceReference> references_;
/** Indices into `references_`. Determines what data is instanced. */
blender::Vector<int> reference_handles_;
Vector<int> reference_handles_;
/** Transformation of the instances. */
blender::Vector<blender::float4x4> transforms_;
Vector<float4x4> transforms_;
/* These almost unique ids are generated based on the `id` attribute, which might not contain
* unique ids at all. They are *almost* unique, because under certain very unlikely
* circumstances, they are not unique. Code using these ids should not crash when they are not
* unique but can generally expect them to be unique. */
mutable std::mutex almost_unique_ids_mutex_;
mutable blender::Array<int> almost_unique_ids_;
mutable Array<int> almost_unique_ids_;
CustomData attributes_;
@ -134,9 +134,9 @@ class Instances {
* argument. For adding many instances, using #resize and accessing the transform array
* directly is preferred.
*/
void add_instance(int instance_handle, const blender::float4x4 &transform);
void add_instance(int instance_handle, const float4x4 &transform);
blender::Span<InstanceReference> references() const;
Span<InstanceReference> references() const;
void remove_unused_references();
/**
@ -152,10 +152,10 @@ class Instances {
*/
GeometrySet &geometry_set_from_reference(int reference_index);
blender::Span<int> reference_handles() const;
blender::MutableSpan<int> reference_handles();
blender::MutableSpan<blender::float4x4> transforms();
blender::Span<blender::float4x4> transforms() const;
Span<int> reference_handles() const;
MutableSpan<int> reference_handles();
MutableSpan<float4x4> transforms();
Span<float4x4> transforms() const;
int instances_num() const;
int references_num() const;
@ -164,21 +164,20 @@ class Instances {
* Remove the indices that are not contained in the mask input, and remove unused instance
* references afterwards.
*/
void remove(const blender::IndexMask &mask,
const blender::bke::AnonymousAttributePropagationInfo &propagation_info);
void remove(const IndexMask &mask, const AnonymousAttributePropagationInfo &propagation_info);
/**
* Get an id for every instance. These can be used for e.g. motion blur.
*/
blender::Span<int> almost_unique_ids() const;
Span<int> almost_unique_ids() const;
blender::bke::AttributeAccessor attributes() const;
blender::bke::MutableAttributeAccessor attributes_for_write();
bke::AttributeAccessor attributes() const;
bke::MutableAttributeAccessor attributes_for_write();
CustomData &custom_data_attributes();
const CustomData &custom_data_attributes() const;
void foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
bool owns_direct_data() const;
void ensure_owns_direct_data();

View File

@ -13,6 +13,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h" /* #BoundBox. */
#include "BKE_customdata.h"
@ -236,7 +237,7 @@ void BKE_mesh_sharp_edges_set_from_angle(struct Mesh *me, float angle);
*/
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob);
BoundBox BKE_mesh_boundbox_get(struct Object *ob);
void BKE_mesh_texspace_calc(struct Mesh *me);
void BKE_mesh_texspace_ensure(struct Mesh *me);

View File

@ -9,10 +9,13 @@
* \brief General operations, lookup, etc. for blender objects.
*/
#include <optional>
#include "BLI_compiler_attrs.h"
#include "BLI_sys_types.h"
#include "DNA_object_enums.h"
#include "DNA_object_types.h" /* #BoundBox. */
#include "DNA_userdef_enums.h"
struct Base;
@ -344,7 +347,7 @@ void BKE_boundbox_minmax(const BoundBox *bb,
float r_min[3],
float r_max[3]);
const BoundBox *BKE_object_boundbox_get(Object *ob);
std::optional<BoundBox> BKE_object_boundbox_get(Object *ob);
void BKE_object_dimensions_get(Object *ob, float r_vec[3]);
/**
* The original scale and object matrix can be passed in so any difference

View File

@ -9,12 +9,12 @@
* \brief A BVH for high poly meshes.
*/
#include <optional>
#include <string>
#include "BLI_bitmap.h"
#include "BLI_compiler_compat.h"
#include "BLI_function_ref.hh"
#include "BLI_ghash.h"
#include "BLI_math_vector_types.hh"
#include "BLI_offset_indices.hh"
#include "BLI_vector.hh"
@ -433,9 +433,10 @@ bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, PBVHFrustumPlanes *frust
*/
bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, PBVHFrustumPlanes *frustum);
GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
const blender::Set<BMFace *, 0> &BKE_pbvh_bmesh_node_faces(PBVHNode *node);
/**
* In order to perform operations on the original node coordinates
* (currently just ray-cast), store the node's triangles and vertices.
@ -517,8 +518,10 @@ struct PBVHVertexIter {
bool is_mesh;
/* bmesh */
GSetIterator bm_unique_verts;
GSetIterator bm_other_verts;
std::optional<blender::Set<BMVert *, 0>::Iterator> bm_unique_verts;
std::optional<blender::Set<BMVert *, 0>::Iterator> bm_unique_verts_end;
std::optional<blender::Set<BMVert *, 0>::Iterator> bm_other_verts;
std::optional<blender::Set<BMVert *, 0>::Iterator> bm_other_verts_end;
CustomData *bm_vdata;
int cd_vert_mask_offset;
@ -579,13 +582,13 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi.mask = vi.vmask ? vi.vmask[vi.index] : 0.0f; \
} \
else { \
if (!BLI_gsetIterator_done(&vi.bm_unique_verts)) { \
vi.bm_vert = (BMVert *)BLI_gsetIterator_getKey(&vi.bm_unique_verts); \
BLI_gsetIterator_step(&vi.bm_unique_verts); \
if (*vi.bm_unique_verts != *vi.bm_unique_verts_end) { \
vi.bm_vert = **vi.bm_unique_verts; \
(*vi.bm_unique_verts)++; \
} \
else { \
vi.bm_vert = (BMVert *)BLI_gsetIterator_getKey(&vi.bm_other_verts); \
BLI_gsetIterator_step(&vi.bm_other_verts); \
vi.bm_vert = **vi.bm_other_verts; \
(*vi.bm_other_verts)++; \
} \
vi.visible = !BM_elem_flag_test_bool(vi.bm_vert, BM_ELEM_HIDDEN); \
if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
@ -620,7 +623,7 @@ struct PBVHFaceIter {
const PBVHNode *node_;
PBVHType pbvh_type_;
int verts_size_;
GSetIterator bm_faces_iter_;
std::optional<blender::Set<BMFace *, 0>::Iterator> bm_faces_iter_;
int cd_hide_poly_, cd_face_set_;
bool *hide_poly_;
int *face_sets_;

View File

@ -9,6 +9,8 @@
* \brief General operations for point clouds.
*/
#include "DNA_object_types.h" /* #BoundBox. */
#ifdef __cplusplus
# include <mutex>
@ -74,7 +76,7 @@ struct PointCloud *BKE_pointcloud_new_nomain(int totpoint);
void BKE_pointcloud_nomain_to_pointcloud(struct PointCloud *pointcloud_src,
struct PointCloud *pointcloud_dst);
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
BoundBox BKE_pointcloud_boundbox_get(struct Object *ob);
bool BKE_pointcloud_attribute_required(const struct PointCloud *pointcloud, const char *name);

View File

@ -2956,17 +2956,15 @@ void BKE_pchan_minmax(const Object *ob,
const bArmature *arm = static_cast<const bArmature *>(ob->data);
Object *ob_custom = (arm->flag & ARM_NO_CUSTOM) ? nullptr : pchan->custom;
const bPoseChannel *pchan_tx = (ob_custom && pchan->custom_tx) ? pchan->custom_tx : pchan;
const BoundBox *bb_custom = nullptr;
BoundBox bb_custom_buf;
std::optional<BoundBox> bb_custom;
if (ob_custom) {
float min[3], max[3];
if (use_empty_drawtype && (ob_custom->type == OB_EMPTY) &&
BKE_object_minmax_empty_drawtype(ob_custom, min, max))
{
memset(&bb_custom_buf, 0x0, sizeof(bb_custom_buf));
BKE_boundbox_init_from_minmax(&bb_custom_buf, min, max);
bb_custom = &bb_custom_buf;
bb_custom.emplace();
BKE_boundbox_init_from_minmax(&bb_custom.value(), min, max);
}
else {
bb_custom = BKE_object_boundbox_get(ob_custom);
@ -2984,7 +2982,7 @@ void BKE_pchan_minmax(const Object *ob,
pchan->custom_translation[1],
pchan->custom_translation[2]);
mul_m4_series(mat, ob->object_to_world, tmp, rmat, smat);
BKE_boundbox_minmax(bb_custom, mat, r_min, r_max);
BKE_boundbox_minmax(&bb_custom.value(), mat, r_min, r_max);
}
else {
float vec[3];

View File

@ -170,28 +170,21 @@ void *BKE_curves_add(Main *bmain, const char *name)
return curves;
}
BoundBox *BKE_curves_boundbox_get(Object *ob)
BoundBox BKE_curves_boundbox_get(Object *ob)
{
using namespace blender;
BLI_assert(ob->type == OB_CURVES);
const Curves *curves_id = static_cast<const Curves *>(ob->data);
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
BoundBox bb;
if (const std::optional<Bounds<float3>> bounds = curves.bounds_min_max()) {
BKE_boundbox_init_from_minmax(&bb, bounds->min, bounds->max);
}
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
if (const std::optional<Bounds<float3>> bounds = curves.bounds_min_max()) {
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
}
else {
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
}
else {
BKE_boundbox_init_from_minmax(&bb, float3(-1), float3(1));
}
return ob->runtime.bb;
return bb;
}
bool BKE_curves_attribute_required(const Curves * /*curves*/, const char *name)

View File

@ -1143,26 +1143,21 @@ GreasePencil *BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_
return grease_pencil;
}
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob)
BoundBox BKE_grease_pencil_boundbox_get(Object *ob)
{
using namespace blender;
BLI_assert(ob->type == OB_GREASE_PENCIL);
const GreasePencil *grease_pencil = static_cast<const GreasePencil *>(ob->data);
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
}
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
BoundBox bb;
if (const std::optional<Bounds<float3>> bounds = grease_pencil->bounds_min_max()) {
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
BKE_boundbox_init_from_minmax(&bb, bounds->min, bounds->max);
}
else {
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
BKE_boundbox_init_from_minmax(&bb, float3(-1), float3(1));
}
return ob->runtime.bb;
return bb;
}
static void grease_pencil_evaluate_modifiers(Depsgraph *depsgraph,
@ -1386,6 +1381,30 @@ Material *BKE_grease_pencil_object_material_ensure_active(Object *ob)
return ma;
}
void BKE_grease_pencil_material_remap(GreasePencil *grease_pencil, const uint *remap, int totcol)
{
using namespace blender::bke;
for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
if (base->type != GP_DRAWING) {
continue;
}
greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
MutableAttributeAccessor attributes = drawing.strokes_for_write().attributes_for_write();
SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
"material_index", ATTR_DOMAIN_CURVE);
if (!material_indices) {
return;
}
for (const int i : material_indices.span.index_range()) {
BLI_assert(blender::IndexRange(totcol).contains(remap[material_indices.span[i]]));
UNUSED_VARS_NDEBUG(totcol);
material_indices.span[i] = remap[material_indices.span[i]];
}
material_indices.finish();
}
}
/** \} */
/* ------------------------------------------------------------------- */

View File

@ -129,7 +129,7 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
/* Do first point. */
const bGPDspoint &first_pt = stroke_points.first();
stroke_positions.first() = float3(first_pt.x, first_pt.y, first_pt.z);
/* Previously, Grease Pencil used a radius convention where 1 "px" = 0.001 units. This "px" was
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px` was
* the brush size which would be stored in the stroke thickness and then scaled by the point
* pressure factor. Finally, the render engine would divide this thickness value by 2000 (we're
* going from a thickness to a radius, hence the factor of two) to convert back into blender

View File

@ -53,6 +53,7 @@
#include "BKE_displist.h"
#include "BKE_editmesh.h"
#include "BKE_gpencil_legacy.h"
#include "BKE_grease_pencil.hh"
#include "BKE_icons.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
@ -1112,6 +1113,9 @@ void BKE_object_material_remap(Object *ob, const uint *remap)
else if (ob->type == OB_GPENCIL_LEGACY) {
BKE_gpencil_material_remap(static_cast<bGPdata *>(ob->data), remap, ob->totcol);
}
else if (ob->type == OB_GREASE_PENCIL) {
BKE_grease_pencil_material_remap(static_cast<GreasePencil *>(ob->data), remap, ob->totcol);
}
else {
/* add support for this object data! */
BLI_assert(matar == nullptr);

View File

@ -1154,28 +1154,20 @@ void BKE_mesh_ensure_default_orig_index_customdata_no_check(Mesh *mesh)
ensure_orig_index_layer(mesh->face_data, mesh->faces_num);
}
BoundBox *BKE_mesh_boundbox_get(Object *ob)
BoundBox BKE_mesh_boundbox_get(Object *ob)
{
/* This is Object-level data access,
* DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
Mesh *me = static_cast<Mesh *>(ob->data);
float min[3], max[3];
Mesh *me = static_cast<Mesh *>(ob->data);
float min[3], max[3];
INIT_MINMAX(min, max);
if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
INIT_MINMAX(min, max);
if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
return ob->runtime.bb;
BoundBox bb;
BKE_boundbox_init_from_minmax(&bb, min, max);
return bb;
}
void BKE_mesh_texspace_calc(Mesh *me)

View File

@ -514,7 +514,7 @@ static void construct_interface_as_legacy_sockets(bNodeTree *ntree)
auto make_legacy_socket = [&](const bNodeTreeInterfaceSocket &socket,
eNodeSocketInOut in_out) -> bNodeSocket * {
bNodeSocket *iosock = make_socket(
ntree, in_out, socket.socket_type, socket.name, socket.identifier);
ntree, in_out, socket.socket_type, socket.name ? socket.name : "", socket.identifier);
if (!iosock) {
return nullptr;
}
@ -1087,11 +1087,11 @@ void node_update_asset_metadata(bNodeTree &node_tree)
auto outputs = idprop::create_group("outputs");
node_tree.ensure_interface_cache();
for (const bNodeTreeInterfaceSocket *socket : node_tree.interface_inputs()) {
auto property = idprop::create(socket->name, socket->socket_type);
auto property = idprop::create(socket->name ? socket->name : "", socket->socket_type);
IDP_AddToGroup(inputs.get(), property.release());
}
for (const bNodeTreeInterfaceSocket *socket : node_tree.interface_outputs()) {
auto property = idprop::create(socket->name, socket->socket_type);
auto property = idprop::create(socket->name ? socket->name : "", socket->socket_type);
IDP_AddToGroup(outputs.get(), property.release());
}
BKE_asset_metadata_idprop_ensure(asset_data, inputs.release());

View File

@ -423,10 +423,9 @@ static void item_copy(bNodeTreeInterfaceItem &dst,
bNodeTreeInterfaceSocket &dst_socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(dst);
const bNodeTreeInterfaceSocket &src_socket =
reinterpret_cast<const bNodeTreeInterfaceSocket &>(src);
BLI_assert(src_socket.name != nullptr);
BLI_assert(src_socket.socket_type != nullptr);
dst_socket.name = BLI_strdup(src_socket.name);
dst_socket.name = BLI_strdup_null(src_socket.name);
dst_socket.description = BLI_strdup_null(src_socket.description);
dst_socket.socket_type = BLI_strdup(src_socket.socket_type);
dst_socket.default_attribute_name = BLI_strdup_null(src_socket.default_attribute_name);
@ -444,9 +443,8 @@ static void item_copy(bNodeTreeInterfaceItem &dst,
bNodeTreeInterfacePanel &dst_panel = reinterpret_cast<bNodeTreeInterfacePanel &>(dst);
const bNodeTreeInterfacePanel &src_panel = reinterpret_cast<const bNodeTreeInterfacePanel &>(
src);
BLI_assert(src_panel.name != nullptr);
dst_panel.name = BLI_strdup(src_panel.name);
dst_panel.name = BLI_strdup_null(src_panel.name);
dst_panel.description = BLI_strdup_null(src_panel.description);
dst_panel.identifier = generate_uid ? generate_uid() : src_panel.identifier;

View File

@ -3558,46 +3558,36 @@ void BKE_boundbox_minmax(const BoundBox *bb,
}
}
const BoundBox *BKE_object_boundbox_get(Object *ob)
std::optional<BoundBox> BKE_object_boundbox_get(Object *ob)
{
BoundBox *bb = nullptr;
switch (ob->type) {
case OB_MESH:
bb = BKE_mesh_boundbox_get(ob);
break;
return BKE_mesh_boundbox_get(ob);
case OB_CURVES_LEGACY:
case OB_SURF:
case OB_FONT:
bb = BKE_curve_boundbox_get(ob);
break;
return *BKE_curve_boundbox_get(ob);
case OB_MBALL:
bb = BKE_mball_boundbox_get(ob);
break;
if (const BoundBox *bb = BKE_mball_boundbox_get(ob)) {
return *bb;
}
return std::nullopt;
case OB_LATTICE:
bb = BKE_lattice_boundbox_get(ob);
break;
return *BKE_lattice_boundbox_get(ob);
case OB_ARMATURE:
bb = BKE_armature_boundbox_get(ob);
break;
return *BKE_armature_boundbox_get(ob);
case OB_GPENCIL_LEGACY:
bb = BKE_gpencil_boundbox_get(ob);
break;
return *BKE_gpencil_boundbox_get(ob);
case OB_CURVES:
bb = BKE_curves_boundbox_get(ob);
break;
return BKE_curves_boundbox_get(ob);
case OB_POINTCLOUD:
bb = BKE_pointcloud_boundbox_get(ob);
break;
return BKE_pointcloud_boundbox_get(ob);
case OB_VOLUME:
bb = BKE_volume_boundbox_get(ob);
break;
return *BKE_volume_boundbox_get(ob);
case OB_GREASE_PENCIL:
bb = BKE_grease_pencil_boundbox_get(ob);
default:
break;
return BKE_grease_pencil_boundbox_get(ob);
}
return bb;
return std::nullopt;
}
void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
@ -3663,8 +3653,7 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
void BKE_object_dimensions_get(Object *ob, float r_vec[3])
{
const BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
if (const std::optional<BoundBox> bb = BKE_object_boundbox_get(ob)) {
float3 scale;
mat4_to_size(scale, ob->object_to_world);
@ -3683,8 +3672,7 @@ void BKE_object_dimensions_set_ex(Object *ob,
const float ob_scale_orig[3],
const float ob_obmat_orig[4][4])
{
const BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
if (const std::optional<BoundBox> bb = BKE_object_boundbox_get(ob)) {
float3 len;
len.x = bb->vec[4][0] - bb->vec[0][0];
len.y = bb->vec[2][1] - bb->vec[0][1];
@ -3728,7 +3716,7 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
break;
}
case OB_MESH: {
const BoundBox bb = *BKE_mesh_boundbox_get(ob);
const BoundBox bb = BKE_mesh_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
@ -3772,13 +3760,13 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
break;
}
case OB_CURVES: {
const BoundBox bb = *BKE_curves_boundbox_get(ob);
const BoundBox bb = BKE_curves_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
}
case OB_POINTCLOUD: {
const BoundBox bb = *BKE_pointcloud_boundbox_get(ob);
const BoundBox bb = BKE_pointcloud_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
@ -3790,7 +3778,7 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
break;
}
case OB_GREASE_PENCIL: {
const BoundBox bb = *BKE_grease_pencil_boundbox_get(ob);
const BoundBox bb = BKE_grease_pencil_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
@ -3978,9 +3966,7 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
/* Do not modify the original bounding-box. */
temp_ob.runtime.bb = nullptr;
BKE_object_replace_data_on_shallow_copy(&temp_ob, dob->ob_data);
const BoundBox *bb = BKE_object_boundbox_get(&temp_ob);
if (bb) {
if (const std::optional<BoundBox> bb = BKE_object_boundbox_get(&temp_ob)) {
int i;
for (i = 0; i < 8; i++) {
float3 vec;

View File

@ -243,13 +243,11 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/** Bounding box from evaluated geometry. */
static void object_sync_boundbox_to_original(Object *object_orig, Object *object_eval)
{
const BoundBox *bb = object_eval->runtime.bb;
if (!bb || (bb->flag & BOUNDBOX_DIRTY)) {
if (!object_eval->runtime.bb || (object_eval->runtime.bb->flag & BOUNDBOX_DIRTY)) {
BKE_object_boundbox_calc_from_evaluated_geometry(object_eval);
}
bb = BKE_object_boundbox_get(object_eval);
if (bb != nullptr) {
if (const std::optional<BoundBox> bb = BKE_object_boundbox_get(object_eval)) {
if (object_orig->runtime.bb == nullptr) {
object_orig->runtime.bb = MEM_new<BoundBox>(__func__);
}

View File

@ -722,9 +722,7 @@ static void pbvh_draw_args_init(const Mesh &mesh, PBVH *pbvh, PBVH_GPU_Args *arg
args->vert_data = &args->bm->vdata;
args->loop_data = &args->bm->ldata;
args->face_data = &args->bm->pdata;
args->bm_faces = node->bm_faces;
args->bm_other_verts = node->bm_other_verts;
args->bm_unique_vert = node->bm_unique_verts;
args->bm_faces = &node->bm_faces;
args->cd_mask_layer = CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK);
break;
@ -1019,16 +1017,6 @@ void BKE_pbvh_free(PBVH *pbvh)
if (node.draw_batches) {
DRW_pbvh_node_free(node.draw_batches);
}
if (node.bm_faces) {
BLI_gset_free(node.bm_faces, nullptr);
}
if (node.bm_unique_verts) {
BLI_gset_free(node.bm_unique_verts, nullptr);
}
if (node.bm_other_verts) {
BLI_gset_free(node.bm_other_verts, nullptr);
}
}
if (node.flag & (PBVH_Leaf | PBVH_TexLeaf)) {
@ -1623,23 +1611,14 @@ static void pbvh_grids_node_visibility_update(PBVH *pbvh, PBVHNode *node)
static void pbvh_bmesh_node_visibility_update(PBVHNode *node)
{
GSet *unique, *other;
unique = BKE_pbvh_bmesh_node_unique_verts(node);
other = BKE_pbvh_bmesh_node_other_verts(node);
GSetIterator gs_iter;
GSET_ITER (gs_iter, unique) {
BMVert *v = static_cast<BMVert *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMVert *v : node->bm_unique_verts) {
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
BKE_pbvh_node_fully_hidden_set(node, false);
return;
}
}
GSET_ITER (gs_iter, other) {
BMVert *v = static_cast<BMVert *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMVert *v : node->bm_other_verts) {
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
BKE_pbvh_node_fully_hidden_set(node, false);
return;
@ -1994,9 +1973,9 @@ void BKE_pbvh_node_num_verts(const PBVH *pbvh,
}
break;
case PBVH_BMESH:
tot = BLI_gset_len(node->bm_unique_verts);
tot = node->bm_unique_verts.size();
if (r_totvert) {
*r_totvert = tot + BLI_gset_len(node->bm_other_verts);
*r_totvert = tot + node->bm_other_verts.size();
}
if (r_uniquevert) {
*r_uniquevert = tot;
@ -3113,8 +3092,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->is_mesh = !pbvh->vert_positions.is_empty();
if (pbvh->header.type == PBVH_BMESH) {
BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts);
BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts);
vi->bm_unique_verts = node->bm_unique_verts.begin();
vi->bm_unique_verts_end = node->bm_unique_verts.end();
vi->bm_other_verts = node->bm_other_verts.begin();
vi->bm_other_verts_end = node->bm_other_verts.end();
vi->bm_vdata = &pbvh->header.bm->vdata;
vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK);
}
@ -3373,13 +3354,13 @@ static void pbvh_face_iter_step(PBVHFaceIter *fd, bool do_step)
switch (fd->pbvh_type_) {
case PBVH_BMESH: {
if (do_step) {
BLI_gsetIterator_step(&fd->bm_faces_iter_);
if (BLI_gsetIterator_done(&fd->bm_faces_iter_)) {
(*fd->bm_faces_iter_)++;
if (*fd->bm_faces_iter_ == fd->node_->bm_faces.end()) {
return;
}
}
BMFace *f = (BMFace *)BLI_gsetIterator_getKey(&fd->bm_faces_iter_);
BMFace *f = **fd->bm_faces_iter_;
fd->face.i = intptr_t(f);
fd->index = f->head.index;
@ -3493,7 +3474,7 @@ void BKE_pbvh_face_iter_init(PBVH *pbvh, PBVHNode *node, PBVHFaceIter *fd)
fd->cd_hide_poly_ = CustomData_get_offset_named(
&pbvh->header.bm->pdata, CD_PROP_INT32, ".hide_poly");
BLI_gsetIterator_init(&fd->bm_faces_iter_, node->bm_faces);
fd->bm_faces_iter_ = node->bm_faces.begin();
break;
}
@ -3516,7 +3497,7 @@ bool BKE_pbvh_face_iter_done(PBVHFaceIter *fd)
case PBVH_GRIDS:
return fd->prim_index_ >= fd->node_->prim_indices.size();
case PBVH_BMESH:
return BLI_gsetIterator_done(&fd->bm_faces_iter_);
return *fd->bm_faces_iter_ == fd->node_->bm_faces.end();
default:
BLI_assert_unreachable();
return true;

View File

@ -199,19 +199,12 @@ static void pbvh_bmesh_node_finalize(PBVH *pbvh,
const int cd_vert_node_offset,
const int cd_face_node_offset)
{
GSetIterator gs_iter;
PBVHNode *n = &pbvh->nodes[node_index];
bool has_visible = false;
/* Create vert hash sets. */
n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
BB_reset(&n->vb);
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : n->bm_faces) {
/* Update ownership of faces. */
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
@ -221,12 +214,12 @@ static void pbvh_bmesh_node_finalize(PBVH *pbvh,
do {
BMVert *v = l_iter->v;
if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
if (!n->bm_unique_verts.contains(v)) {
if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
BLI_gset_add(n->bm_other_verts, v);
n->bm_other_verts.add(v);
}
else {
BLI_gset_insert(n->bm_unique_verts, v);
n->bm_unique_verts.add(v);
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
}
}
@ -258,7 +251,7 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const Span<BBC> bbc_array, int nod
const int cd_face_node_offset = pbvh->cd_face_node_offset;
PBVHNode *n = &pbvh->nodes[node_index];
if (BLI_gset_len(n->bm_faces) <= pbvh->leaf_limit) {
if (n->bm_faces.size() <= pbvh->leaf_limit) {
/* Node limit not exceeded. */
pbvh_bmesh_node_finalize(pbvh, node_index, cd_vert_node_offset, cd_face_node_offset);
return;
@ -267,9 +260,7 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const Span<BBC> bbc_array, int nod
/* Calculate bounding box around primitive centroids. */
BB cb;
BB_reset(&cb);
GSetIterator gs_iter;
GSET_ITER (gs_iter, n->bm_faces) {
const BMFace *f = static_cast<const BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : n->bm_faces) {
const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
BB_expand(&cb, bbc->bcentroid);
@ -291,37 +282,36 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const Span<BBC> bbc_array, int nod
PBVHNode *c1 = &pbvh->nodes[children], *c2 = &pbvh->nodes[children + 1];
c1->flag |= PBVH_Leaf;
c2->flag |= PBVH_Leaf;
c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
c2->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
c1->bm_faces.reserve(n->bm_faces.size() / 2);
c2->bm_faces.reserve(n->bm_faces.size() / 2);
/* Partition the parent node's faces between the two children. */
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : n->bm_faces) {
const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
if (bbc->bcentroid[axis] < mid) {
BLI_gset_insert(c1->bm_faces, f);
c1->bm_faces.add(f);
}
else {
BLI_gset_insert(c2->bm_faces, f);
c2->bm_faces.add(f);
}
}
/* Enforce at least one primitive in each node */
GSet *empty = nullptr, *other;
if (BLI_gset_len(c1->bm_faces) == 0) {
empty = c1->bm_faces;
other = c2->bm_faces;
blender::Set<BMFace *, 0> *empty = nullptr;
blender::Set<BMFace *, 0> *other;
if (c1->bm_faces.is_empty()) {
empty = &c1->bm_faces;
other = &c2->bm_faces;
}
else if (BLI_gset_len(c2->bm_faces) == 0) {
empty = c2->bm_faces;
other = c1->bm_faces;
else if (c2->bm_faces.is_empty()) {
empty = &c2->bm_faces;
other = &c1->bm_faces;
}
if (empty) {
GSET_ITER (gs_iter, other) {
void *key = BLI_gsetIterator_getKey(&gs_iter);
BLI_gset_insert(empty, key);
BLI_gset_remove(other, key, nullptr);
for (BMFace *f : *other) {
empty->add(f);
other->remove(f);
break;
}
}
@ -329,32 +319,20 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const Span<BBC> bbc_array, int nod
/* Clear this node */
/* Mark this node's unique verts as unclaimed. */
if (n->bm_unique_verts) {
GSET_ITER (gs_iter, n->bm_unique_verts) {
BMVert *v = static_cast<BMVert *>(BLI_gsetIterator_getKey(&gs_iter));
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
}
BLI_gset_free(n->bm_unique_verts, nullptr);
for (BMVert *v : n->bm_unique_verts) {
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
}
/* Unclaim faces. */
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : n->bm_faces) {
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
}
BLI_gset_free(n->bm_faces, nullptr);
if (n->bm_other_verts) {
BLI_gset_free(n->bm_other_verts, nullptr);
}
n->bm_faces.clear_and_shrink();
if (n->layer_disp) {
MEM_freeN(n->layer_disp);
}
n->bm_faces = nullptr;
n->bm_unique_verts = nullptr;
n->bm_other_verts = nullptr;
n->layer_disp = nullptr;
if (n->draw_batches) {
@ -379,8 +357,8 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const Span<BBC> bbc_array, int nod
/* Recursively split the node if it exceeds the leaf_limit. */
static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
{
GSet *bm_faces = pbvh->nodes[node_index].bm_faces;
const int faces_num = BLI_gset_len(bm_faces);
PBVHNode &node = pbvh->nodes[node_index];
const int faces_num = node.bm_faces.size();
if (faces_num <= pbvh->leaf_limit) {
/* Node limit not exceeded */
return false;
@ -392,10 +370,8 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
/* For each BMFace, store the AABB and AABB centroid. */
Array<BBC> bbc_array(faces_num);
GSetIterator gs_iter;
int i;
GSET_ITER_INDEX (gs_iter, bm_faces, i) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
int i = 0;
for (BMFace *f : node.bm_faces) {
BBC *bbc = &bbc_array[i];
BB_reset((BB *)bbc);
@ -408,7 +384,9 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
/* So we can do direct lookups on 'bbc_array'. */
BM_elem_index_set(f, i); /* set_dirty! */
i++;
}
/* Likely this is already dirty. */
pbvh->header.bm->elem_index_dirty |= BM_FACE;
@ -465,7 +443,7 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
/* This value is logged below. */
copy_v3_v3(v->no, no);
BLI_gset_insert(node->bm_unique_verts, v);
node->bm_unique_verts.add(v);
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index);
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
@ -494,7 +472,7 @@ static BMFace *pbvh_bmesh_face_create(PBVH *pbvh,
pbvh->header.bm, v_tri.data(), e_tri.data(), 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
node->bm_faces.add(f);
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, node_index);
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_TopologyUpdated;
@ -557,13 +535,13 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *pbvh, PBVHNode *new_owner,
BLI_assert(current_owner != new_owner);
/* Remove current ownership. */
BLI_gset_remove(current_owner->bm_unique_verts, v, nullptr);
current_owner->bm_unique_verts.remove(v);
/* Set new ownership */
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, new_owner - pbvh->nodes.data());
BLI_gset_insert(new_owner->bm_unique_verts, v);
BLI_gset_remove(new_owner->bm_other_verts, v, nullptr);
BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v));
new_owner->bm_unique_verts.add(v);
new_owner->bm_other_verts.remove(v);
BLI_assert(!new_owner->bm_other_verts.contains(v));
new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
}
@ -574,7 +552,7 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
int f_node_index_prev = DYNTOPO_NODE_NONE;
PBVHNode *v_node = pbvh_bmesh_node_from_vert(pbvh, v);
BLI_gset_remove(v_node->bm_unique_verts, v, nullptr);
v_node->bm_unique_verts.remove(v);
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node. */
@ -590,10 +568,10 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated;
/* Remove current ownership. */
BLI_gset_remove(f_node->bm_other_verts, v, nullptr);
f_node->bm_other_verts.remove(v);
BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
BLI_assert(!f_node->bm_unique_verts.contains(v));
BLI_assert(!f_node->bm_other_verts.contains(v));
}
}
BM_FACES_OF_VERT_ITER_END;
@ -609,7 +587,7 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
do {
BMVert *v = l_iter->v;
if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, f_node, v, 1)) {
if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
if (f_node->bm_unique_verts.contains(v)) {
/* Find a different node that uses 'v'. */
PBVHNode *new_node;
@ -622,13 +600,13 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
}
else {
/* Remove from other verts. */
BLI_gset_remove(f_node->bm_other_verts, v, nullptr);
f_node->bm_other_verts.remove(v);
}
}
} while ((l_iter = l_iter->next) != l_first);
/* Remove face from node and top level. */
BLI_gset_remove(f_node->bm_faces, f, nullptr);
f_node->bm_faces.remove(f);
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
/* Log removed face. */
@ -975,12 +953,7 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
if ((node.flag & PBVH_Leaf) && (node.flag & PBVH_UpdateTopology) &&
!(node.flag & PBVH_FullyHidden))
{
GSetIterator gs_iter;
/* Check each face. */
GSET_ITER (gs_iter, node.bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : node.bm_faces) {
long_edge_queue_face_add(eq_ctx, f);
}
}
@ -1033,12 +1006,7 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
if ((node.flag & PBVH_Leaf) && (node.flag & PBVH_UpdateTopology) &&
!(node.flag & PBVH_FullyHidden))
{
GSetIterator gs_iter;
/* Check each face */
GSET_ITER (gs_iter, node.bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : node.bm_faces) {
short_edge_queue_face_add(eq_ctx, f);
}
}
@ -1148,8 +1116,8 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *pbvh, BMEdge *
BM_face_kill(bm, f_adj);
/* Ensure new vertex is in the node */
if (!BLI_gset_haskey(pbvh->nodes[ni].bm_unique_verts, v_new)) {
BLI_gset_add(pbvh->nodes[ni].bm_other_verts, v_new);
if (!pbvh->nodes[ni].bm_unique_verts.contains(v_new)) {
pbvh->nodes[ni].bm_other_verts.add(v_new);
}
if (BM_vert_edge_count_is_over(v_opp, 8)) {
@ -1271,8 +1239,8 @@ static void pbvh_bmesh_collapse_edge(
pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f);
/* Ensure that v_conn is in the new face's node */
if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
BLI_gset_add(n->bm_other_verts, v_conn);
if (!n->bm_unique_verts.contains(v_conn)) {
n->bm_other_verts.add(v_conn);
}
}
@ -1411,8 +1379,6 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
use_original = use_original && node->bm_tot_ortri;
GSetIterator gs_iter;
if (use_original && node->bm_tot_ortri) {
for (int i = 0; i < node->bm_tot_ortri; i++) {
float *cos[3];
@ -1443,9 +1409,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
}
}
else {
GSET_ITER (gs_iter, node->bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : node->bm_faces) {
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
@ -1491,13 +1455,10 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
return false;
}
GSetIterator gs_iter;
bool hit = false;
BMFace *f_hit = nullptr;
GSET_ITER (gs_iter, node->bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : node->bm_faces) {
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
@ -1549,11 +1510,7 @@ bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
}
}
else {
GSetIterator gs_iter;
GSET_ITER (gs_iter, node->bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : node->bm_faces) {
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
@ -1572,17 +1529,14 @@ void pbvh_bmesh_normals_update(Span<PBVHNode *> nodes)
{
for (PBVHNode *node : nodes) {
if (node->flag & PBVH_UpdateNormals) {
GSetIterator gs_iter;
GSET_ITER (gs_iter, node->bm_faces) {
BM_face_normal_update(static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter)));
for (BMFace *face : node->bm_faces) {
BM_face_normal_update(face);
}
GSET_ITER (gs_iter, node->bm_unique_verts) {
BM_vert_normal_update(static_cast<BMVert *>(BLI_gsetIterator_getKey(&gs_iter)));
for (BMVert *vert : node->bm_unique_verts) {
BM_vert_normal_update(vert);
}
/* This should be unneeded normally */
GSET_ITER (gs_iter, node->bm_other_verts) {
BM_vert_normal_update(static_cast<BMVert *>(BLI_gsetIterator_getKey(&gs_iter)));
for (BMVert *vert : node->bm_other_verts) {
BM_vert_normal_update(vert);
}
node->flag &= ~PBVH_UpdateNormals;
}
@ -1730,11 +1684,7 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
bool has_visible = false;
n->flag = PBVH_Leaf;
n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface);
/* Create vert hash sets */
n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
n->bm_faces.reserve(node->totface);
BB_reset(&n->vb);
@ -1745,7 +1695,7 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
BBC *bbc = &bbc_array[BM_elem_index_get(f)];
/* Update ownership of faces. */
BLI_gset_insert(n->bm_faces, f);
n->bm_faces.add_new(f);
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
/* Update vertices. */
@ -1753,12 +1703,12 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
BMLoop *l_iter = l_first;
do {
BMVert *v = l_iter->v;
if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
if (!n->bm_unique_verts.contains(v)) {
if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
BLI_gset_add(n->bm_other_verts, v);
n->bm_other_verts.add(v);
}
else {
BLI_gset_insert(n->bm_unique_verts, v);
n->bm_unique_verts.add(v);
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
}
}
@ -1955,9 +1905,9 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, BMLog *log, PBVHNode *node, bool u
return;
}
const int totvert = BLI_gset_len(node->bm_unique_verts) + BLI_gset_len(node->bm_other_verts);
const int totvert = node->bm_unique_verts.size() + node->bm_other_verts.size();
const int tottri = BLI_gset_len(node->bm_faces);
const int tottri = node->bm_faces.size();
node->bm_orco = static_cast<float(*)[3]>(
MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__));
@ -1967,9 +1917,7 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, BMLog *log, PBVHNode *node, bool u
/* Copy out the vertices and assign a temporary index. */
int i = 0;
GSetIterator gs_iter;
GSET_ITER (gs_iter, node->bm_unique_verts) {
BMVert *v = static_cast<BMVert *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMVert *v : node->bm_unique_verts) {
const float *origco = BM_log_original_vert_co(log, v);
if (use_original && origco) {
@ -1983,8 +1931,7 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, BMLog *log, PBVHNode *node, bool u
BM_elem_index_set(v, i); /* set_dirty! */
i++;
}
GSET_ITER (gs_iter, node->bm_other_verts) {
BMVert *v = static_cast<BMVert *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMVert *v : node->bm_other_verts) {
const float *origco = BM_log_original_vert_co(log, v);
if (use_original && origco) {
@ -2003,13 +1950,10 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, BMLog *log, PBVHNode *node, bool u
/* Copy the triangles */
i = 0;
GSET_ITER (gs_iter, node->bm_faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : node->bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
bm_face_as_array_index_tri(f, node->bm_ortri[i]);
i++;
}
@ -2042,17 +1986,17 @@ void BKE_pbvh_node_mark_topology_update(PBVHNode *node)
node->flag |= PBVH_UpdateTopology;
}
GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node)
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node)
{
return node->bm_unique_verts;
}
GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node)
const blender::Set<BMVert *, 0> &BKE_pbvh_bmesh_node_other_verts(PBVHNode *node)
{
return node->bm_other_verts;
}
GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
const blender::Set<BMFace *, 0> &BKE_pbvh_bmesh_node_faces(PBVHNode *node)
{
return node->bm_faces;
}
@ -2141,8 +2085,8 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
int totface = 0, totvert = 0;
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *n = &pbvh->nodes[i];
totface += n->bm_faces ? BLI_gset_len(n->bm_faces) : 0;
totvert += n->bm_unique_verts ? BLI_gset_len(n->bm_unique_verts) : 0;
totface += n->bm_faces.is_empty() ? n->bm_faces.size() : 0;
totvert += n->bm_unique_verts ? n->bm_unique_verts.size() : 0;
}
BLI_assert(totface == BLI_gset_len(faces_all));
@ -2160,7 +2104,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
BLI_assert(n->flag & PBVH_Leaf);
/* Check that the face's node knows it owns the face. */
BLI_assert(BLI_gset_haskey(n->bm_faces, f));
BLI_assert(n->bm_faces.contains(f));
/* Check the face's vertices... */
BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
@ -2251,8 +2195,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
if (n->flag & PBVH_Leaf) {
GSetIterator gs_iter;
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
for (BMFace *f : n->bm_faces) {
PBVHNode *n_other = pbvh_bmesh_node_lookup(pbvh, f);
BLI_assert(n == n_other);
BLI_assert(BLI_gset_haskey(faces_all, f));

View File

@ -6,6 +6,7 @@
#include "BLI_array.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_set.hh"
#include "BLI_span.hh"
#include "BLI_vector.hh"
@ -17,6 +18,8 @@
struct PBVHGPUFormat;
struct MLoopTri;
struct BMVert;
struct BMFace;
/* Axis-aligned bounding box */
struct BB {
@ -107,13 +110,13 @@ struct PBVHNode {
/* Dyntopo */
/* GSet of pointers to the BMFaces used by this node.
/* Set of pointers to the BMFaces used by this node.
* NOTE: PBVH_BMESH only. Faces are always triangles
* (dynamic topology forcibly triangulates the mesh).
*/
GSet *bm_faces = nullptr;
GSet *bm_unique_verts = nullptr;
GSet *bm_other_verts = nullptr;
blender::Set<BMFace *, 0> bm_faces;
blender::Set<BMVert *, 0> bm_unique_verts;
blender::Set<BMVert *, 0> bm_other_verts;
/* Deprecated. Stores original coordinates of triangles. */
float (*bm_orco)[3] = nullptr;

View File

@ -259,16 +259,10 @@ std::optional<blender::Bounds<blender::float3>> PointCloud::bounds_min_max() con
return this->runtime->bounds_cache.data();
}
BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
BoundBox BKE_pointcloud_boundbox_get(Object *ob)
{
using namespace blender;
BLI_assert(ob->type == OB_POINTCLOUD);
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
}
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
std::optional<Bounds<float3>> bounds;
if (ob->runtime.geometry_set_eval) {
@ -279,14 +273,15 @@ BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
bounds = pointcloud->bounds_min_max();
}
BoundBox bb;
if (bounds) {
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
BKE_boundbox_init_from_minmax(&bb, bounds->min, bounds->max);
}
else {
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
BKE_boundbox_init_from_minmax(&bb, float3(-1), float3(1));
}
return ob->runtime.bb;
return bb;
}
bool BKE_pointcloud_attribute_required(const PointCloud * /*pointcloud*/, const char *name)

View File

@ -492,8 +492,7 @@ static rbCollisionShape *rigidbody_validate_sim_shape_helper(RigidBodyWorld *rbw
*/
/* XXX: all dimensions are auto-determined now... later can add stored settings for this */
/* get object dimensions without scaling */
const BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
if (const std::optional<BoundBox> bb = BKE_object_boundbox_get(ob)) {
size[0] = (bb->vec[4][0] - bb->vec[0][0]);
size[1] = (bb->vec[2][1] - bb->vec[0][1]);
size[2] = (bb->vec[1][2] - bb->vec[0][2]);
@ -1769,7 +1768,7 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyO
float(*positions)[3] = reinterpret_cast<float(*)[3]>(
mesh->vert_positions_for_write().data());
int totvert = mesh->totvert;
const BoundBox *bb = BKE_object_boundbox_get(ob);
const std::optional<BoundBox> bb = BKE_object_boundbox_get(ob);
RB_shape_trimesh_update(static_cast<rbCollisionShape *>(rbo->shared->physics_shape),
(float *)positions,

View File

@ -849,8 +849,8 @@ static void version_principled_bsdf_specular_tint(bNodeTree *ntree)
static float one[] = {1.0f, 1.0f, 1.0f, 1.0f};
/* If any of the two inputs is dynamic, we add a Mix node. */
if (base_color_sock->link || specular_tint_sock->link) {
/* Add a mix node when working with dynamic inputs. */
if (specular_tint_sock->link || (base_color_sock->link && specular_tint_old != 0)) {
bNode *mix = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX);
static_cast<NodeShaderMix *>(mix->storage)->data_type = SOCK_RGBA;
mix->locx = node->locx - 170;
@ -891,7 +891,7 @@ static void version_copy_socket(bNodeTreeInterfaceSocket &dst,
char *identifier)
{
/* Node socket copy function based on bNodeTreeInterface::item_copy to avoid using blenkernel. */
dst.name = BLI_strdup(src.name);
dst.name = BLI_strdup_null(src.name);
dst.description = BLI_strdup_null(src.description);
dst.socket_type = BLI_strdup(src.socket_type);
dst.default_attribute_name = BLI_strdup_null(src.default_attribute_name);
@ -1062,7 +1062,7 @@ static void enable_geometry_nodes_is_modifier(Main &bmain)
static void versioning_grease_pencil_stroke_radii_scaling(GreasePencil *grease_pencil)
{
using namespace blender;
/* Previously, Grease Pencil used a radius convention where 1 "px" = 0.001 units. This "px" was
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px` was
* the brush size which would be stored in the stroke thickness and then scaled by the point
* pressure factor. Finally, the render engine would divide this thickness value by 2000 (we're
* going from a thickness to a radius, hence the factor of two) to convert back into blender

View File

@ -547,7 +547,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
blo_update_defaults_scene(bmain, scene);
if (app_template && STREQ(app_template, "Video_Editing")) {
if (app_template &&
(STREQ(app_template, "Video_Editing") || STREQ(app_template, "2D_Animation"))) {
/* Filmic is too slow, use standard until it is optimized. */
STRNCPY(scene->view_settings.view_transform, "Standard");
STRNCPY(scene->view_settings.look, "None");
@ -555,7 +556,13 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
else {
/* Default to AgX view transform. */
STRNCPY(scene->view_settings.view_transform, "AgX");
}
if (app_template && STREQ(app_template, "Video_Editing")) {
/* Pass: no extra tweaks needed. Keep the view settings configured above, and rely on the
* default state of enabled AV sync. */
}
else {
/* AV Sync break physics sim caching, disable until that is fixed. */
scene->audio.flag &= ~AUDIO_SYNC;
scene->flag &= ~SCE_FRAME_DROP;

View File

@ -149,11 +149,6 @@ static CLG_LogRef LOG = {"blo.writefile"};
/** \name Internal Write Wrapper's (Abstracts Compression)
* \{ */
enum eWriteWrapType {
WW_WRAP_NONE = 1,
WW_WRAP_ZSTD,
};
struct ZstdFrame {
ZstdFrame *next, *prev;
@ -161,70 +156,94 @@ struct ZstdFrame {
uint32_t uncompressed_size;
};
struct WriteWrap {
/* callbacks */
bool (*open)(WriteWrap *ww, const char *filepath);
bool (*close)(WriteWrap *ww);
size_t (*write)(WriteWrap *ww, const char *data, size_t data_len);
class WriteWrap {
public:
virtual bool open(const char *filepath) = 0;
virtual bool close() = 0;
virtual bool write(const void *buf, size_t buf_len) = 0;
/* Buffer output (we only want when output isn't already buffered). */
bool use_buf;
/* internal */
int file_handle;
struct {
ListBase threadpool;
ListBase tasks;
ThreadMutex mutex;
ThreadCondition condition;
int next_frame;
int num_frames;
int level;
ListBase frames;
bool write_error;
} zstd;
/** Buffer output (we only want when output isn't already buffered). */
bool use_buf = true;
};
/* none */
static bool ww_open_none(WriteWrap *ww, const char *filepath)
class RawWriteWrap : public WriteWrap {
public:
bool open(const char *filepath) override;
bool close() override;
bool write(const void *buf, size_t buf_len) override;
private:
int file_handle = 0;
};
bool RawWriteWrap::open(const char *filepath)
{
int file;
file = BLI_open(filepath, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
if (file != -1) {
ww->file_handle = file;
file_handle = file;
return true;
}
return false;
}
static bool ww_close_none(WriteWrap *ww)
bool RawWriteWrap::close()
{
return (close(ww->file_handle) != -1);
return (::close(file_handle) != -1);
}
static size_t ww_write_none(WriteWrap *ww, const char *buf, size_t buf_len)
bool RawWriteWrap::write(const void *buf, size_t buf_len)
{
return write(ww->file_handle, buf, buf_len);
return ::write(file_handle, buf, buf_len) == buf_len;
}
/* zstd */
class ZstdWriteWrap : public WriteWrap {
WriteWrap &base_wrap;
struct ZstdWriteBlockTask {
ListBase threadpool = {};
ListBase tasks = {};
ThreadMutex mutex = {};
ThreadCondition condition = {};
int next_frame = 0;
int num_frames = 0;
int level = 0;
ListBase frames = {};
bool write_error = false;
public:
ZstdWriteWrap(WriteWrap &base_wrap) : base_wrap(base_wrap) {}
bool open(const char *filepath) override;
bool close() override;
bool write(const void *buf, size_t buf_len) override;
private:
struct ZstdWriteBlockTask;
void write_task(ZstdWriteBlockTask *task);
void write_u32_le(uint32_t val);
void write_seekable_frames();
};
struct ZstdWriteWrap::ZstdWriteBlockTask {
ZstdWriteBlockTask *next, *prev;
void *data;
size_t size;
int frame_number;
WriteWrap *ww;
ZstdWriteWrap *ww;
static void *write_task(void *userdata)
{
auto *task = static_cast<ZstdWriteBlockTask *>(userdata);
task->ww->write_task(task);
return nullptr;
}
};
static void *zstd_write_task(void *userdata)
void ZstdWriteWrap::write_task(ZstdWriteBlockTask *task)
{
ZstdWriteBlockTask *task = static_cast<ZstdWriteBlockTask *>(userdata);
WriteWrap *ww = task->ww;
size_t out_buf_len = ZSTD_compressBound(task->size);
void *out_buf = MEM_mallocN(out_buf_len, "Zstd out buffer");
size_t out_size = ZSTD_compress(
@ -232,58 +251,57 @@ static void *zstd_write_task(void *userdata)
MEM_freeN(task->data);
BLI_mutex_lock(&ww->zstd.mutex);
BLI_mutex_lock(&mutex);
while (ww->zstd.next_frame != task->frame_number) {
BLI_condition_wait(&ww->zstd.condition, &ww->zstd.mutex);
while (next_frame != task->frame_number) {
BLI_condition_wait(&condition, &mutex);
}
if (ZSTD_isError(out_size)) {
ww->zstd.write_error = true;
write_error = true;
}
else {
if (ww_write_none(ww, static_cast<const char *>(out_buf), out_size) == out_size) {
if (base_wrap.write(out_buf, out_size)) {
ZstdFrame *frameinfo = static_cast<ZstdFrame *>(
MEM_mallocN(sizeof(ZstdFrame), "zstd frameinfo"));
frameinfo->uncompressed_size = task->size;
frameinfo->compressed_size = out_size;
BLI_addtail(&ww->zstd.frames, frameinfo);
BLI_addtail(&frames, frameinfo);
}
else {
ww->zstd.write_error = true;
write_error = true;
}
}
ww->zstd.next_frame++;
next_frame++;
BLI_mutex_unlock(&ww->zstd.mutex);
BLI_condition_notify_all(&ww->zstd.condition);
BLI_mutex_unlock(&mutex);
BLI_condition_notify_all(&condition);
MEM_freeN(out_buf);
return nullptr;
}
static bool ww_open_zstd(WriteWrap *ww, const char *filepath)
bool ZstdWriteWrap::open(const char *filepath)
{
if (!ww_open_none(ww, filepath)) {
if (!base_wrap.open(filepath)) {
return false;
}
/* Leave one thread open for the main writing logic, unless we only have one HW thread. */
int num_threads = max_ii(1, BLI_system_thread_count() - 1);
BLI_threadpool_init(&ww->zstd.threadpool, zstd_write_task, num_threads);
BLI_mutex_init(&ww->zstd.mutex);
BLI_condition_init(&ww->zstd.condition);
BLI_threadpool_init(&threadpool, ZstdWriteBlockTask::write_task, num_threads);
BLI_mutex_init(&mutex);
BLI_condition_init(&condition);
return true;
}
static void zstd_write_u32_le(WriteWrap *ww, uint32_t val)
void ZstdWriteWrap::write_u32_le(uint32_t val)
{
#ifdef __BIG_ENDIAN__
BLI_endian_switch_uint32(&val);
#endif
ww_write_none(ww, (char *)&val, sizeof(uint32_t));
base_wrap.write(&val, sizeof(uint32_t));
}
/* In order to implement efficient seeking when reading the .blend, we append
@ -294,49 +312,49 @@ static void zstd_write_u32_le(WriteWrap *ww, uint32_t val)
* If this information is not present in a file (e.g. if it was compressed
* with external tools), it can still be opened in Blender, but seeking will
* not be supported, so more memory might be needed. */
static void zstd_write_seekable_frames(WriteWrap *ww)
void ZstdWriteWrap::write_seekable_frames()
{
/* Write seek table header (magic number and frame size). */
zstd_write_u32_le(ww, 0x184D2A5E);
write_u32_le(0x184D2A5E);
/* The actual frame number might not match ww->zstd.num_frames if there was a write error. */
const uint32_t num_frames = BLI_listbase_count(&ww->zstd.frames);
/* The actual frame number might not match num_frames if there was a write error. */
const uint32_t num_frames = BLI_listbase_count(&frames);
/* Each frame consists of two u32, so 8 bytes each.
* After the frames, a footer containing two u32 and one byte (9 bytes total) is written. */
const uint32_t frame_size = num_frames * 8 + 9;
zstd_write_u32_le(ww, frame_size);
write_u32_le(frame_size);
/* Write seek table entries. */
LISTBASE_FOREACH (ZstdFrame *, frame, &ww->zstd.frames) {
zstd_write_u32_le(ww, frame->compressed_size);
zstd_write_u32_le(ww, frame->uncompressed_size);
LISTBASE_FOREACH (ZstdFrame *, frame, &frames) {
write_u32_le(frame->compressed_size);
write_u32_le(frame->uncompressed_size);
}
/* Write seek table footer (number of frames, option flags and second magic number). */
zstd_write_u32_le(ww, num_frames);
write_u32_le(num_frames);
const char flags = 0; /* We don't store checksums for each frame. */
ww_write_none(ww, &flags, 1);
zstd_write_u32_le(ww, 0x8F92EAB1);
base_wrap.write(&flags, 1);
write_u32_le(0x8F92EAB1);
}
static bool ww_close_zstd(WriteWrap *ww)
bool ZstdWriteWrap::close()
{
BLI_threadpool_end(&ww->zstd.threadpool);
BLI_freelistN(&ww->zstd.tasks);
BLI_threadpool_end(&threadpool);
BLI_freelistN(&tasks);
BLI_mutex_end(&ww->zstd.mutex);
BLI_condition_end(&ww->zstd.condition);
BLI_mutex_end(&mutex);
BLI_condition_end(&condition);
zstd_write_seekable_frames(ww);
BLI_freelistN(&ww->zstd.frames);
write_seekable_frames();
BLI_freelistN(&frames);
return ww_close_none(ww) && !ww->zstd.write_error;
return base_wrap.close() && !write_error;
}
static size_t ww_write_zstd(WriteWrap *ww, const char *buf, size_t buf_len)
bool ZstdWriteWrap::write(const void *buf, size_t buf_len)
{
if (ww->zstd.write_error) {
return 0;
if (write_error) {
return false;
}
ZstdWriteBlockTask *task = static_cast<ZstdWriteBlockTask *>(
@ -344,54 +362,30 @@ static size_t ww_write_zstd(WriteWrap *ww, const char *buf, size_t buf_len)
task->data = MEM_mallocN(buf_len, __func__);
memcpy(task->data, buf, buf_len);
task->size = buf_len;
task->frame_number = ww->zstd.num_frames++;
task->ww = ww;
task->frame_number = num_frames++;
task->ww = this;
BLI_mutex_lock(&ww->zstd.mutex);
BLI_addtail(&ww->zstd.tasks, task);
BLI_mutex_lock(&mutex);
BLI_addtail(&tasks, task);
/* If there's a free worker thread, just push the block into that thread.
* Otherwise, we wait for the earliest thread to finish.
* We look up the earliest thread while holding the mutex, but release it
* before joining the thread to prevent a deadlock. */
ZstdWriteBlockTask *first_task = static_cast<ZstdWriteBlockTask *>(ww->zstd.tasks.first);
BLI_mutex_unlock(&ww->zstd.mutex);
if (!BLI_available_threads(&ww->zstd.threadpool)) {
BLI_threadpool_remove(&ww->zstd.threadpool, first_task);
ZstdWriteBlockTask *first_task = static_cast<ZstdWriteBlockTask *>(tasks.first);
BLI_mutex_unlock(&mutex);
if (!BLI_available_threads(&threadpool)) {
BLI_threadpool_remove(&threadpool, first_task);
/* If the task list was empty before we pushed our task, there should
* always be a free thread. */
BLI_assert(first_task != task);
BLI_remlink(&ww->zstd.tasks, first_task);
BLI_remlink(&tasks, first_task);
MEM_freeN(first_task);
}
BLI_threadpool_insert(&ww->zstd.threadpool, task);
BLI_threadpool_insert(&threadpool, task);
return buf_len;
}
/* --- end compression types --- */
static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww)
{
memset(r_ww, 0, sizeof(*r_ww));
switch (ww_type) {
case WW_WRAP_ZSTD: {
r_ww->open = ww_open_zstd;
r_ww->close = ww_close_zstd;
r_ww->write = ww_write_zstd;
r_ww->use_buf = true;
break;
}
default: {
r_ww->open = ww_open_none;
r_ww->close = ww_close_none;
r_ww->write = ww_write_none;
r_ww->use_buf = true;
break;
}
}
return true;
}
/** \} */
@ -483,7 +477,7 @@ static void writedata_do_write(WriteData *wd, const void *mem, size_t memlen)
BLO_memfile_chunk_add(&wd->mem, static_cast<const char *>(mem), memlen);
}
else {
if (wd->ww->write(wd->ww, static_cast<const char *>(mem), memlen) != memlen) {
if (!wd->ww->write(mem, memlen)) {
wd->error = true;
}
}
@ -1463,23 +1457,17 @@ static void write_file_main_validate_post(Main *bmain, ReportList *reports)
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name File Writing (Public)
* \{ */
bool BLO_write_file(Main *mainvar,
const char *filepath,
const int write_flags,
const BlendFileWriteParams *params,
ReportList *reports)
static bool BLO_write_file_impl(Main *mainvar,
const char *filepath,
const int write_flags,
const BlendFileWriteParams *params,
ReportList *reports,
WriteWrap &ww)
{
BLI_assert(!BLI_path_is_rel(filepath));
BLI_assert(BLI_path_is_abs_from_cwd(filepath));
char tempname[FILE_MAX + 1];
WriteWrap ww;
eBLO_WritePathRemap remap_mode = params->remap_mode;
const bool use_save_versions = params->use_save_versions;
@ -1498,9 +1486,7 @@ bool BLO_write_file(Main *mainvar,
/* open temporary file, so we preserve the original in case we crash */
SNPRINTF(tempname, "%s@", filepath);
ww_handle_init((write_flags & G_FILE_COMPRESS) ? WW_WRAP_ZSTD : WW_WRAP_NONE, &ww);
if (ww.open(&ww, tempname) == false) {
if (ww.open(tempname) == false) {
BKE_reportf(
reports, RPT_ERROR, "Cannot open file %s for writing: %s", tempname, strerror(errno));
return false;
@ -1593,7 +1579,7 @@ bool BLO_write_file(Main *mainvar,
const bool err = write_file_handle(
mainvar, &ww, nullptr, nullptr, write_flags, use_userdef, thumb);
ww.close(&ww);
ww.close();
if (UNLIKELY(path_list_backup)) {
BKE_bpath_list_restore(mainvar, path_list_flag, path_list_backup);
@ -1626,6 +1612,26 @@ bool BLO_write_file(Main *mainvar,
return true;
}
/* -------------------------------------------------------------------- */
/** \name File Writing (Public)
* \{ */
bool BLO_write_file(Main *mainvar,
const char *filepath,
const int write_flags,
const BlendFileWriteParams *params,
ReportList *reports)
{
RawWriteWrap raw_wrap;
if (write_flags & G_FILE_COMPRESS) {
ZstdWriteWrap zstd_wrap(raw_wrap);
return BLO_write_file_impl(mainvar, filepath, write_flags, params, reports, zstd_wrap);
}
return BLO_write_file_impl(mainvar, filepath, write_flags, params, reports, raw_wrap);
}
bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
{
bool use_userdef = false;

View File

@ -262,16 +262,16 @@ struct Render;
* If this is the case the chunk will be added to the work-list for OpenCLDevice's
* otherwise the chunk will be added to the work-list of CPUDevices.
*
* A thread will read the work-list and sends a workpackage to its device.
* A thread will read the work-list and sends a work-package to its device.
*
* \see WorkScheduler.schedule method that is called to schedule a chunk
* \see Device.execute method called to execute a chunk
*
* \subsection CPUDevice CPUDevice
* When a CPUDevice gets a WorkPackage the Device will get the inputbuffer that is needed to
* When a CPUDevice gets a WorkPackage the Device will get the input-buffer that is needed to
* calculate the chunk. Allocation is already done by the ExecutionGroup.
* The outputbuffer of the chunk is being created.
* The OutputOperation of the ExecutionGroup is called to execute the area of the outputbuffer.
* The output-buffer of the chunk is being created.
* The OutputOperation of the ExecutionGroup is called to execute the area of the output-buffer.
*
* \see ExecutionGroup
* \see NodeOperation.execute_region executes a single chunk of a NodeOperation

View File

@ -305,15 +305,15 @@ class ExecutionGroup {
void init_execution();
/**
* \brief get all inputbuffers needed to calculate an chunk
* \note all inputbuffers must be executed
* \brief get all input-buffers needed to calculate an chunk
* \note all input-buffers must be executed
* \param chunk_number: the chunk to be calculated
* \return `(MemoryBuffer **)` the input-buffers.
*/
MemoryBuffer **get_input_buffers_opencl(int chunk_number);
/**
* \brief allocate the outputbuffer of a chunk
* \brief allocate the output-buffer of a chunk
* \param chunk_number: the number of the chunk in the ExecutionGroup
* \param rect: the rect of that chunk
* \see determine_chunk_rect

View File

@ -470,7 +470,7 @@ class NodeOperation {
* \param rect: the rectangle of the chunk (location and size)
* \param chunk_number: the chunk_number to be calculated
* \param memory_buffers: all input MemoryBuffer's needed
* \param output_buffer: the outputbuffer to write to
* \param output_buffer: the output-buffer to write to
*/
virtual void execute_opencl_region(OpenCLDevice * /*device*/,
rcti * /*rect*/,

View File

@ -103,10 +103,10 @@ void WriteBufferOperation::execute_opencl_region(OpenCLDevice *device,
float *output_float_buffer = output_buffer->get_buffer();
cl_int error;
/*
* 1. create cl_mem from outputbuffer
* 2. call NodeOperation (input) executeOpenCLChunk(.....)
* 3. schedule read back from opencl to main device (outputbuffer)
* 4. schedule native callback
* 1. create cl_mem from output_buffer.
* 2. call NodeOperation (input) executeOpenCLChunk(...).
* 3. schedule read back from OPENCL to main device (output_buffer).
* 4. schedule native callback.
*
* NOTE: list of cl_mem will be filled by 2, and needs to be cleaned up by 4
*/

View File

@ -695,6 +695,7 @@ set(GLSL_SRC
engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
engines/gpencil/shaders/grease_pencil_depth_merge_vert.glsl
engines/gpencil/shaders/gpencil_vfx_frag.glsl
engines/gpencil/gpencil_defines.h

View File

@ -13,14 +13,11 @@
#include "BLI_bitmap.h"
#include "BLI_math_vector_types.hh"
#include "BLI_offset_indices.hh"
#include "BLI_set.hh"
#include "BLI_span.hh"
#include "BKE_ccg.h"
#ifdef __cplusplus
extern "C" {
#endif
class PBVHAttrReq;
struct GPUBatch;
struct PBVHNode;
@ -33,6 +30,7 @@ struct MLoopTri;
struct CustomData;
struct SubdivCCG;
struct BMesh;
struct BMFace;
struct PBVH_GPU_Args {
int pbvh_type;
@ -72,7 +70,7 @@ struct PBVH_GPU_Args {
PBVHNode *node;
/* BMesh. */
GSet *bm_unique_vert, *bm_other_verts, *bm_faces;
const blender::Set<BMFace *, 0> *bm_faces;
int cd_mask_layer;
};
@ -94,7 +92,3 @@ GPUBatch *DRW_pbvh_lines_get(PBVHBatches *batches,
const PBVH_GPU_Args &args,
int *r_prim_count,
bool do_coarse_grids);
#ifdef __cplusplus
}
#endif

View File

@ -155,12 +155,12 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
}
/* Update World AABB in frontbuffer. */
const BoundBox *bb = BKE_object_boundbox_get(ob);
const BoundBox bb = *BKE_object_boundbox_get(ob);
float min[3], max[3];
INIT_MINMAX(min, max);
for (int i = 0; i < 8; i++) {
float vec[3];
copy_v3_v3(vec, bb->vec[i]);
copy_v3_v3(vec, bb.vec[i]);
mul_m4_v3(ob->object_to_world, vec);
minmax_v3v3_v3(min, max, vec);
}

View File

@ -42,7 +42,7 @@ VolumeModule::GridAABB::GridAABB(Object *ob, const Camera &camera, const Volumes
return int3(grid_coords * float3(data.tex_size) + 0.5);
};
const BoundBox &bbox = *BKE_object_boundbox_get(ob);
const BoundBox bbox = *BKE_object_boundbox_get(ob);
min = int3(INT32_MAX);
max = int3(INT32_MIN);

View File

@ -63,11 +63,11 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob)
* strokes not aligned with the object axes. Maybe we could try to
* compute the minimum axis of all strokes. But this would be more
* computationally heavy and should go into the GPData evaluation. */
const BoundBox *bbox = BKE_object_boundbox_get(ob);
const std::optional<BoundBox> bbox = BKE_object_boundbox_get(ob);
/* Convert bbox to matrix */
float mat[4][4], size[3], center[3];
BKE_boundbox_calc_size_aabb(bbox, size);
BKE_boundbox_calc_center_aabb(bbox, center);
BKE_boundbox_calc_size_aabb(&bbox.value(), size);
BKE_boundbox_calc_center_aabb(&bbox.value(), center);
unit_m4(mat);
copy_v3_v3(mat[3], center);
/* Avoid division by 0.0 later. */

View File

@ -140,7 +140,7 @@ class Instance {
{
switch (object_ref.object->type) {
case OB_GREASE_PENCIL:
objects.sync_grease_pencil(manager, object_ref, main_fb_, main_ps_);
objects.sync_grease_pencil(manager, object_ref, main_fb_, depth_tx_, main_ps_);
break;
case OB_LAMP:
lights.sync(object_ref);

View File

@ -8,6 +8,8 @@
#pragma once
#include "BLI_math_quaternion_types.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_image.h"
#include "DRW_gpu_wrapper.hh"
@ -52,8 +54,11 @@ class ObjectModule {
bool use_stroke_fill_ = true;
bool use_vfx_ = true;
bool is_render_ = true;
bool is_persp_ = true;
/** Forward vector used to sort gpencil objects. */
float3 camera_forward_;
float3 camera_pos_;
/** Scene current frame. */
float current_frame_ = 0;
@ -90,12 +95,14 @@ class ObjectModule {
void begin_sync(Depsgraph *depsgraph, const View &main_view)
{
camera_forward_ = float3(main_view.viewinv()[2]);
camera_forward_ = main_view.forward();
camera_pos_ = main_view.location();
current_frame_ = DEG_get_ctime(depsgraph);
is_object_fb_needed_ = false;
is_layer_fb_needed_ = false;
is_persp_ = main_view.is_persp();
/* TODO(fclem): Shrink buffer. */
// objects_buf_.shrink();
}
@ -103,12 +110,13 @@ class ObjectModule {
void sync_grease_pencil(Manager &manager,
ObjectRef &object_ref,
Framebuffer &main_fb,
TextureFromPool &depth_tx,
PassSortable &main_ps)
{
using namespace blender::bke::greasepencil;
Object *object = object_ref.object;
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
const GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
if (grease_pencil.drawings().is_empty()) {
return;
@ -188,6 +196,14 @@ class ObjectModule {
object_subpass.draw(geom, handle);
}
float4x4 plane_mat = get_object_plane_mat(*object);
ResourceHandle handle_plane_mat = manager.resource_handle(plane_mat);
object_subpass.framebuffer_set(&DRW_viewport_framebuffer_list_get()->depth_only_fb);
object_subpass.state_set(DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_DEPTH);
object_subpass.shader_set(shaders_.static_shader_get(DEPTH_MERGE));
object_subpass.bind_texture("depthBuf", (object_has_vfx) ? nullptr : &depth_tx);
object_subpass.draw(DRW_cache_quad_get(), handle_plane_mat);
/* TODO: Do object VFX. */
#if 0
if (object_has_vfx) {
@ -249,6 +265,56 @@ class ObjectModule {
{
return objects_buf_.size() > 0;
}
float4x4 get_object_plane_mat(const Object &object)
{
using namespace math;
/* Find the normal most likely to represent the gpObject. */
/* TODO: This does not work quite well if you use
* strokes not aligned with the object axes. Maybe we could try to
* compute the minimum axis of all strokes. But this would be more
* computationally heavy and should go into the GPData evaluation. */
BLI_assert(object.type == OB_GREASE_PENCIL);
const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(object.data);
const std::optional<Bounds<float3>> bounds = grease_pencil.bounds_min_max();
if (!bounds) {
return float4x4::identity();
}
/* Convert bbox to matrix */
const float3 size = float3(bounds->max - bounds->min) + 1e-8f;
const float3 center = midpoint(bounds->min, bounds->max);
/* BBox space to World. */
const float4x4 object_to_world = float4x4(object.object_to_world);
float4x4 bbox_mat = object_to_world *
from_loc_rot_scale<float4x4>(center, Quaternion::identity(), size);
float3 plane_normal;
if (is_persp_) {
/* BBox center to camera vector. */
plane_normal = camera_pos_ - bbox_mat.location();
}
else {
plane_normal = camera_forward_;
}
/* World to BBox space. */
float4x4 bbox_mat_inv = invert(bbox_mat);
/* mat_inv_t is a "normal" matrix which will transform
* BBox normal space to world space. */
float4x4 bbox_mat_inv_t = transpose(bbox_mat_inv);
/* Normalize the vector in BBox space. */
plane_normal = normalize(transform_direction(bbox_mat_inv, plane_normal));
plane_normal = normalize(transform_direction(bbox_mat_inv_t, plane_normal));
/* Define a matrix that will be used to render a triangle to merge the depth of the rendered
* gpencil object with the rest of the scene. */
float4x4 plane_mat = from_up_axis<float4x4>(plane_normal);
float radius = length(transform_direction(object_to_world, size));
plane_mat = scale(plane_mat, float3(radius));
plane_mat.location() = transform_point(object_to_world, center);
return plane_mat;
}
};
} // namespace blender::draw::greasepencil

View File

@ -74,7 +74,7 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
case LAYER_BLEND:
return "gpencil_layer_blend";
case DEPTH_MERGE:
return "gpencil_depth_merge";
return "grease_pencil_depth_merge";
case MASK_INVERT:
return "gpencil_mask_invert";
case FX_COMPOSITE:

View File

@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2020-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
void main()
{
gl_Position = drw_point_object_to_homogenous(pos);
}

View File

@ -126,6 +126,16 @@ GPU_SHADER_CREATE_INFO(gpencil_depth_merge)
.depth_write(DepthWrite::ANY)
.additional_info("draw_view");
GPU_SHADER_CREATE_INFO(grease_pencil_depth_merge)
.do_static_compilation(true)
.define("strokeOrder3d", "false")
.sampler(0, ImageType::DEPTH_2D, "depthBuf")
.vertex_in(0, Type::VEC3, "pos")
.vertex_source("grease_pencil_depth_merge_vert.glsl")
.fragment_source("gpencil_depth_merge_frag.glsl")
.depth_write(DepthWrite::ANY)
.additional_info("draw_modelmat_new", "draw_view");
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -360,21 +360,21 @@ static void OVERLAY_bounds(OVERLAY_ExtraCallBuffers *cb,
return;
}
const BoundBox *bb = BKE_object_boundbox_get(ob);
std::optional<BoundBox> bb = BKE_object_boundbox_get(ob);
BoundBox bb_local;
if (bb == nullptr) {
if (!bb) {
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
BKE_boundbox_init_from_minmax(&bb_local, min, max);
bb = &bb_local;
bb.emplace(bb_local);
}
BKE_boundbox_calc_size_aabb(bb, size);
BKE_boundbox_calc_size_aabb(&*bb, size);
if (around_origin) {
zero_v3(center);
}
else {
BKE_boundbox_calc_center_aabb(bb, center);
BKE_boundbox_calc_center_aabb(&*bb, center);
}
switch (boundtype) {

View File

@ -33,11 +33,11 @@ static void gpencil_depth_plane(Object *ob, float r_plane[4])
* strokes not aligned with the object axes. Maybe we could try to
* compute the minimum axis of all strokes. But this would be more
* computationally heavy and should go into the GPData evaluation. */
const BoundBox *bbox = BKE_object_boundbox_get(ob);
const BoundBox bbox = *BKE_object_boundbox_get(ob);
/* Convert bbox to matrix */
float mat[4][4], size[3], center[3];
BKE_boundbox_calc_size_aabb(bbox, size);
BKE_boundbox_calc_center_aabb(bbox, center);
BKE_boundbox_calc_size_aabb(&bbox, size);
BKE_boundbox_calc_center_aabb(&bbox, center);
unit_m4(mat);
copy_v3_v3(mat[3], center);
/* Avoid division by 0.0 later. */

View File

@ -40,8 +40,7 @@ vec3 extrude_offset(vec3 ls_P)
float signed_distance = dot(pass_data.far_plane.xyz, ws_P) - pass_data.far_plane.w;
extrude_distance = -signed_distance / L_dot_FP;
}
vec3 ls_light_direction = normal_world_to_object(vec3(pass_data.light_direction_ws));
return ls_light_direction * extrude_distance;
return pass_data.light_direction_ws * extrude_distance;
}
void emit_cap(const bool front, bool reversed, int triangle_vertex_id)
@ -87,13 +86,16 @@ void main()
/* Calculate front/back Positions. */
vData[0].frontPosition = point_object_to_ndc(vData[0].pos);
vData[0].backPosition = point_object_to_ndc(vData[0].pos + extrude_offset(vData[0].pos));
vData[0].backPosition = point_world_to_ndc(point_object_to_world(vData[0].pos) +
extrude_offset(vData[0].pos));
vData[1].frontPosition = point_object_to_ndc(vData[1].pos);
vData[1].backPosition = point_object_to_ndc(vData[1].pos + extrude_offset(vData[1].pos));
vData[1].backPosition = point_world_to_ndc(point_object_to_world(vData[1].pos) +
extrude_offset(vData[1].pos));
vData[2].frontPosition = point_object_to_ndc(vData[2].pos);
vData[2].backPosition = point_object_to_ndc(vData[2].pos + extrude_offset(vData[2].pos));
vData[2].backPosition = point_world_to_ndc(point_object_to_world(vData[2].pos) +
extrude_offset(vData[2].pos));
/* Geometry shader equivalent calc. */
vec3 v10 = vData[0].pos - vData[1].pos;

View File

@ -71,8 +71,7 @@ vec3 extrude_offset(vec3 ls_P)
float signed_distance = dot(pass_data.far_plane.xyz, ws_P) - pass_data.far_plane.w;
extrude_distance = -signed_distance / L_dot_FP;
}
vec3 ls_light_direction = normal_world_to_object(vec3(pass_data.light_direction_ws));
return ls_light_direction * extrude_distance;
return pass_data.light_direction_ws * extrude_distance;
}
void main()
@ -100,16 +99,20 @@ void main()
/* Calculate front/back Positions. */
vData[0].frontPosition = point_object_to_ndc(vData[0].pos);
vData[0].backPosition = point_object_to_ndc(vData[0].pos + extrude_offset(vData[0].pos));
vData[0].backPosition = point_world_to_ndc(point_object_to_world(vData[0].pos) +
extrude_offset(vData[0].pos));
vData[1].frontPosition = point_object_to_ndc(vData[1].pos);
vData[1].backPosition = point_object_to_ndc(vData[1].pos + extrude_offset(vData[1].pos));
vData[1].backPosition = point_world_to_ndc(point_object_to_world(vData[1].pos) +
extrude_offset(vData[1].pos));
vData[2].frontPosition = point_object_to_ndc(vData[2].pos);
vData[2].backPosition = point_object_to_ndc(vData[2].pos + extrude_offset(vData[2].pos));
vData[2].backPosition = point_world_to_ndc(point_object_to_world(vData[2].pos) +
extrude_offset(vData[2].pos));
vData[3].frontPosition = point_object_to_ndc(vData[3].pos);
vData[3].backPosition = point_object_to_ndc(vData[3].pos + extrude_offset(vData[3].pos));
vData[3].backPosition = point_world_to_ndc(point_object_to_world(vData[3].pos) +
extrude_offset(vData[3].pos));
/* Geometry shader equivalent path. */
vec3 v10 = vData[0].pos - vData[1].pos;

View File

@ -183,11 +183,11 @@ void ShadowPass::ShadowView::setup(View &view, float3 light_direction, bool forc
bool ShadowPass::ShadowView::debug_object_culling(Object *ob)
{
printf("Test %s\n", ob->id.name);
const BoundBox *_bbox = BKE_object_boundbox_get(ob);
const BoundBox _bbox = *BKE_object_boundbox_get(ob);
for (int p : IndexRange(extruded_frustum_.planes_count)) {
float4 plane = extruded_frustum_.planes[p];
bool separating_axis = true;
for (float3 corner : _bbox->vec) {
for (float3 corner : _bbox.vec) {
corner = math::transform_point(float4x4(ob->object_to_world), corner);
float signed_distance = math::dot(corner, float3(plane)) - plane.w;
if (signed_distance <= 0) {

View File

@ -861,8 +861,8 @@ class Texture : NonCopyable {
}
/**
* Clear the texture to NaN for floats, or a to debug value for ints.
* (For debugging unitialized data issues)
* Clear the texture to NaN for floats, or a to debug value for integers.
* (For debugging uninitialized data issues)
*/
void debug_clear()
{

View File

@ -604,6 +604,16 @@ void DrawCommandBuf::finalize_commands(Vector<Header, 0> &headers,
cmd.vertex_len = batch_vert_len;
}
#ifdef WITH_METAL_BACKEND
/* For SSBO vertex fetch, mutate output vertex count by ssbo vertex fetch expansion factor. */
if (cmd.shader) {
int num_input_primitives = gpu_get_prim_count_from_type(cmd.vertex_len,
cmd.batch->prim_type);
cmd.vertex_len = num_input_primitives *
GPU_shader_get_ssbo_vertex_fetch_num_verts_per_prim(cmd.shader);
}
#endif
if (cmd.handle.raw > 0) {
/* Save correct offset to start of resource_id buffer region for this draw. */
uint instance_first = resource_id_count;
@ -664,6 +674,20 @@ void DrawMultiBuf::bind(RecordingState &state,
group.vertex_first = group.vertex_first == -1 ? batch_vert_first : group.vertex_first;
group.base_index = batch_base_index;
#ifdef WITH_METAL_BACKEND
/* For SSBO vertex fetch, mutate output vertex count by ssbo vertex fetch expansion factor. */
if (group.gpu_shader) {
int num_input_primitives = gpu_get_prim_count_from_type(group.vertex_len,
group.gpu_batch->prim_type);
group.vertex_len = num_input_primitives *
GPU_shader_get_ssbo_vertex_fetch_num_verts_per_prim(group.gpu_shader);
/* Override base index to -1, as all SSBO calls are submitted as non-indexed, with the
* index buffer indirection handled within the implementation. This is to ensure
* command generation can correctly assigns baseInstance in the non-indexed formatting. */
group.base_index = -1;
}
#endif
/* Instancing attributes are not supported using the new pipeline since we use the base
* instance to set the correct resource_id. Workaround is a storage_buf + gl_InstanceID. */
BLI_assert(batch_inst_len == 1);

View File

@ -302,6 +302,11 @@ struct Draw {
uint vertex_len;
uint vertex_first;
ResourceHandle handle;
#ifdef WITH_METAL_BACKEND
/* Shader is required for extracting SSBO vertex fetch expansion parameters during draw command
* generation. */
GPUShader *shader;
#endif
void execute(RecordingState &state) const;
std::string serialize() const;
@ -411,7 +416,7 @@ union Undetermined {
};
/** Try to keep the command size as low as possible for performance. */
BLI_STATIC_ASSERT(sizeof(Undetermined) <= 24, "One of the command type is too large.")
BLI_STATIC_ASSERT(sizeof(Undetermined) <= /*24*/ 32, "One of the command type is too large.")
/** \} */
@ -447,14 +452,28 @@ class DrawCommandBuf {
uint vertex_len,
uint vertex_first,
ResourceHandle handle,
uint /*custom_id*/)
uint /*custom_id*/
#ifdef WITH_METAL_BACKEND
,
GPUShader *shader = nullptr
#endif
)
{
vertex_first = vertex_first != -1 ? vertex_first : 0;
instance_len = instance_len != -1 ? instance_len : 1;
int64_t index = commands.append_and_get_index({});
headers.append({Type::Draw, uint(index)});
commands[index].draw = {batch, instance_len, vertex_len, vertex_first, handle};
commands[index].draw = {batch,
instance_len,
vertex_len,
vertex_first,
handle
#ifdef WITH_METAL_BACKEND
,
shader
#endif
};
}
void bind(RecordingState &state,
@ -548,7 +567,12 @@ class DrawMultiBuf {
uint vertex_len,
uint vertex_first,
ResourceHandle handle,
uint custom_id)
uint custom_id
#ifdef WITH_METAL_BACKEND
,
GPUShader *shader
#endif
)
{
/* Custom draw-calls cannot be batched and will produce one group per draw. */
const bool custom_group = ((vertex_first != 0 && vertex_first != -1) || vertex_len != -1);
@ -587,6 +611,11 @@ class DrawMultiBuf {
group.back_proto_len = 0;
group.vertex_len = vertex_len;
group.vertex_first = vertex_first;
#ifdef WITH_METAL_BACKEND
/* If SSBO vertex fetch is used, shader must be known to extract vertex expansion parameters.
*/
group.gpu_shader = shader;
#endif
/* Custom group are not to be registered in the group_ids_. */
if (!custom_group) {
group_id = new_group_id;
@ -600,6 +629,11 @@ class DrawMultiBuf {
DrawGroup &group = group_buf_[group_id];
group.len += instance_len;
group.front_facing_len += inverted ? 0 : instance_len;
#ifdef WITH_METAL_BACKEND
/* If SSBO vertex fetch is used, shader must be known to extract vertex expansion parameters.
*/
group.gpu_shader = shader;
#endif
/* For serialization only. */
(inverted ? group.back_proto_len : group.front_proto_len)++;
}

View File

@ -42,6 +42,7 @@ struct DrawGroup {
uint total_counter;
#ifndef GPU_SHADER
/* NOTE: Union just to make sure the struct has always the same size on all platform. */
union {
struct {
@ -50,12 +51,18 @@ struct DrawGroup {
uint back_proto_len;
/** Needed to create the correct draw call. */
GPUBatch *gpu_batch;
# ifdef WITH_METAL_BACKEND
GPUShader *gpu_shader;
# endif
};
struct {
#endif
uint front_facing_counter;
uint back_facing_counter;
uint _pad0, _pad1;
#if defined(WITH_METAL_BACKEND) || defined(GPU_METAL)
uint _pad2, _pad3, _pad4, _pad5;
#endif
#ifndef GPU_SHADER
};
};

View File

@ -730,7 +730,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
static void drw_call_culling_init(DRWCullingState *cull, Object *ob)
{
const BoundBox *bbox;
std::optional<BoundBox> bbox;
if (ob != nullptr && (bbox = BKE_object_boundbox_get(ob))) {
float corner[3];
/* Get BoundSphere center and radius from the BoundBox. */

View File

@ -687,8 +687,24 @@ inline void PassBase<T>::draw(GPUBatch *batch,
return;
}
BLI_assert(shader_);
draw_commands_buf_.append_draw(
headers_, commands_, batch, instance_len, vertex_len, vertex_first, handle, custom_id);
#ifdef WITH_METAL_BACKEND
/* TEMP: Note, shader_ is passed as part of the draw as vertex-expansion properties for SSBO
* vertex fetch need extracting at command generation time. */
GPUShader *draw_shader = GPU_shader_uses_ssbo_vertex_fetch(shader_) ? shader_ : nullptr;
#endif
draw_commands_buf_.append_draw(headers_,
commands_,
batch,
instance_len,
vertex_len,
vertex_first,
handle,
custom_id
#ifdef WITH_METAL_BACKEND
,
draw_shader
#endif
);
}
template<class T>

View File

@ -218,7 +218,7 @@ void extract_data_vert_bmesh(const PBVH_GPU_Args &args, const int cd_offset, GPU
{
VBOT *data = static_cast<VBOT *>(GPU_vertbuf_get_data(&vbo));
GSET_FOREACH_BEGIN (const BMFace *, f, args.bm_faces) {
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
@ -230,7 +230,6 @@ void extract_data_vert_bmesh(const PBVH_GPU_Args &args, const int cd_offset, GPU
*data = convert_value<AttributeT, VBOT>(bmesh_cd_vert_get<AttributeT>(*l->next->v, cd_offset));
data++;
}
GSET_FOREACH_END();
}
template<typename AttributeT, typename VBOT>
@ -238,7 +237,7 @@ void extract_data_corner_bmesh(const PBVH_GPU_Args &args, const int cd_offset, G
{
VBOT *data = static_cast<VBOT *>(GPU_vertbuf_get_data(&vbo));
GSET_FOREACH_BEGIN (const BMFace *, f, args.bm_faces) {
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
@ -250,7 +249,6 @@ void extract_data_corner_bmesh(const PBVH_GPU_Args &args, const int cd_offset, G
*data = convert_value<AttributeT, VBOT>(bmesh_cd_loop_get<AttributeT>(*l->next, cd_offset));
data++;
}
GSET_FOREACH_END();
}
struct PBVHBatch {
@ -353,12 +351,11 @@ struct PBVHBatches {
break;
}
case PBVH_BMESH: {
GSET_FOREACH_BEGIN (BMFace *, f, args.bm_faces) {
for (const BMFace *f : *args.bm_faces) {
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
count++;
}
}
GSET_FOREACH_END();
}
}
@ -866,7 +863,7 @@ struct PBVHBatches {
switch (vbo.type) {
case CD_PBVH_CO_TYPE: {
float3 *data = static_cast<float3 *>(GPU_vertbuf_get_data(vbo.vert_buf));
GSET_FOREACH_BEGIN (const BMFace *, f, args.bm_faces) {
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
@ -878,12 +875,11 @@ struct PBVHBatches {
*data = l->next->v->co;
data++;
}
GSET_FOREACH_END();
break;
}
case CD_PBVH_NO_TYPE: {
short4 *data = static_cast<short4 *>(GPU_vertbuf_get_data(vbo.vert_buf));
GSET_FOREACH_BEGIN (const BMFace *, f, args.bm_faces) {
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
@ -901,7 +897,6 @@ struct PBVHBatches {
data += 3;
}
}
GSET_FOREACH_END();
break;
}
case CD_PBVH_MASK_TYPE: {
@ -923,7 +918,7 @@ struct PBVHBatches {
uchar4 *data = static_cast<uchar4 *>(GPU_vertbuf_get_data(vbo.vert_buf));
if (cd_offset != -1) {
GSET_FOREACH_BEGIN (const BMFace *, f, args.bm_faces) {
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
@ -941,7 +936,6 @@ struct PBVHBatches {
std::fill(data, data + 3, fset_color);
data += 3;
}
GSET_FOREACH_END();
}
else {
MutableSpan(data, GPU_vertbuf_get_vertex_len(vbo.vert_buf)).fill(uchar4(255));
@ -1160,7 +1154,7 @@ struct PBVHBatches {
int v_index = 0;
lines_count = 0;
GSET_FOREACH_BEGIN (BMFace *, f, args.bm_faces) {
for (const BMFace *f : *args.bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
@ -1172,7 +1166,6 @@ struct PBVHBatches {
lines_count += 3;
v_index += 3;
}
GSET_FOREACH_END();
lines_index = GPU_indexbuf_build(&elb_lines);
}

View File

@ -161,8 +161,8 @@ inline void ObjectBounds::sync()
inline void ObjectBounds::sync(Object &ob)
{
const BoundBox *bbox = BKE_object_boundbox_get(&ob);
if (bbox == nullptr) {
const std::optional<BoundBox> bbox = BKE_object_boundbox_get(&ob);
if (!bbox) {
bounding_sphere.w = -1.0f; /* Disable test. */
return;
}

View File

@ -126,6 +126,12 @@ class View {
return data_[view_id].viewinv.location();
}
const float3 &forward(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].viewinv.z_axis();
}
const float4x4 &viewmat(int view_id = 0) const
{
BLI_assert(view_id < view_len_);

View File

@ -177,7 +177,7 @@ static int add_driver_with_target(ReportList * /*reports*/,
if ((RNA_property_unit(dst_prop) == PROP_UNIT_ROTATION) &&
(RNA_property_unit(src_prop) != PROP_UNIT_ROTATION))
{
/* Rotation Destination: normal -> radians, so convert src to radians
/* Rotation Destination: normal -> radians, so convert src to radians
* (However, if both input and output is a rotation, don't apply such corrections)
*/
STRNCPY(driver->expression, "radians(var)");

View File

@ -684,7 +684,7 @@ void ease_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor
const float exponent = 1 + fabs(factor) * 4;
for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
/* For easy calculation of the curve, the values are normalized. */
/* For easy calculation of the curve, the values are normalized. */
const float normalized_x = (fcu->bezt[i].vec[1][0] - left_x) / key_x_range;
float normalized_y = 0;

View File

@ -252,6 +252,11 @@ static int run_node_group_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
if (!node_tree->group_output_node()) {
BKE_report(op->reports, RPT_ERROR, "Node group must have a group output node");
return OPERATOR_CANCELLED;
}
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(
scene, view_layer, CTX_wm_view3d(C), &objects_len, mode);
@ -345,7 +350,7 @@ static void add_attribute_search_or_value_buttons(uiLayout *layout,
uiItemL(name_row, "", ICON_NONE);
}
else {
uiItemL(name_row, socket.name, ICON_NONE);
uiItemL(name_row, socket.name ? socket.name : "", ICON_NONE);
}
uiLayout *prop_row = uiLayoutRow(split, true);
@ -359,7 +364,7 @@ static void add_attribute_search_or_value_buttons(uiLayout *layout,
uiItemR(prop_row, md_ptr, rna_path_attribute_name.c_str(), UI_ITEM_NONE, "", ICON_NONE);
}
else {
const char *name = socket_type == SOCK_BOOLEAN ? socket.name : "";
const char *name = socket_type == SOCK_BOOLEAN ? (socket.name ? socket.name : "") : "";
uiItemR(prop_row, md_ptr, rna_path.c_str(), UI_ITEM_NONE, name, ICON_NONE);
}
@ -399,29 +404,30 @@ static void draw_property_for_socket(const bNodeTree &node_tree,
/* Use #uiItemPointerR to draw pointer properties because #uiItemR would not have enough
* information about what type of ID to select for editing the values. This is because
* pointer IDProperties contain no information about their type. */
const char *name = socket.name ? socket.name : "";
switch (socket_type) {
case SOCK_OBJECT:
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "objects", socket.name, ICON_OBJECT_DATA);
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "objects", name, ICON_OBJECT_DATA);
break;
case SOCK_COLLECTION:
uiItemPointerR(
row, op_ptr, rna_path, bmain_ptr, "collections", socket.name, ICON_OUTLINER_COLLECTION);
row, op_ptr, rna_path, bmain_ptr, "collections", name, ICON_OUTLINER_COLLECTION);
break;
case SOCK_MATERIAL:
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "materials", socket.name, ICON_MATERIAL);
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "materials", name, ICON_MATERIAL);
break;
case SOCK_TEXTURE:
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "textures", socket.name, ICON_TEXTURE);
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "textures", name, ICON_TEXTURE);
break;
case SOCK_IMAGE:
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "images", socket.name, ICON_IMAGE);
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "images", name, ICON_IMAGE);
break;
default:
if (nodes::input_has_attribute_toggle(node_tree, socket_index)) {
add_attribute_search_or_value_buttons(row, op_ptr, socket);
}
else {
uiItemR(row, op_ptr, rna_path, UI_ITEM_NONE, socket.name, ICON_NONE);
uiItemR(row, op_ptr, rna_path, UI_ITEM_NONE, name, ICON_NONE);
}
}
if (!nodes::input_has_attribute_toggle(node_tree, socket_index)) {

View File

@ -1639,9 +1639,6 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE |
GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE |
GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE)) != 0;
/* Calc bound box matrix. */
float bound_mat[4][4];
BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
@ -1662,7 +1659,7 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
/* Check if the stroke collide with brush. */
if ((gps->totpoints > 1) &&
!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat))
!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat))
{
continue;
}
@ -1700,7 +1697,7 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
*/
gpencil_brush_grab_stroke_init(gso, gps_active);
changed |= gpencil_sculpt_brush_do_stroke(
gso, gps, bound_mat, gpencil_brush_grab_store_points);
gso, gps, diff_mat, gpencil_brush_grab_store_points);
}
else {
/* Apply effect to the stored points */

View File

@ -1226,7 +1226,7 @@ void create_suzanne(Main &bmain, Object &object, float4x4 matrix, const int fram
int color_skin_light = add_material_from_template(bmain, object, gp_monkey_material_skin_light);
int color_skin_shadow = add_material_from_template(
bmain, object, gp_monkey_material_skin_shadow);
object.actcol = color_black;
object.actcol = color_black + 1;
const std::array<int, 15> monkey_line_materials({
color_black,

View File

@ -619,7 +619,7 @@ void ui_draw_but_WAVEFORM(ARegion * /*region*/,
int scissor[4];
float colors[3][3];
const float colorsycc[3][3] = {{1, 0, 1}, {1, 1, 0}, {0, 1, 1}};
/* colors pre multiplied by alpha for speed up */
/* Colors pre-multiplied by alpha for speed up. */
float colors_alpha[3][3], colorsycc_alpha[3][3];
float min, max;

View File

@ -3604,7 +3604,11 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
data->undo_stack_text = nullptr;
#ifdef WITH_INPUT_IME
if (win->ime_data) {
/* See #wm_window_IME_end code-comments for details. */
# if defined(WIN32) || defined(__APPLE__)
if (win->ime_data)
# endif
{
ui_textedit_ime_end(win, but);
}
#endif
@ -4017,13 +4021,15 @@ static void ui_do_but_textedit(
}
#ifdef WITH_INPUT_IME
if (ELEM(event->type, WM_IME_COMPOSITE_START, WM_IME_COMPOSITE_EVENT)) {
if (event->type == WM_IME_COMPOSITE_START) {
changed = true;
if (event->type == WM_IME_COMPOSITE_START && but->selend > but->selsta) {
if (but->selend > but->selsta) {
ui_textedit_delete_selection(but, data);
}
if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) {
}
else if (event->type == WM_IME_COMPOSITE_EVENT) {
changed = true;
if (ime_data->result_len) {
if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) &&
STREQ(ime_data->str_result, "\xE3\x80\x82"))
{

View File

@ -740,7 +740,7 @@ static void ui_block_colorpicker(uiBlock *block,
}
UI_but_flag_disable(bt, UI_BUT_UNDO);
bt->hardmax = hardmax; /* not common but rgb may be over 1.0 */
bt->hardmax = hardmax; /* Not common but RGB may be over 1.0. */
UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, nullptr);
bt->custom_data = cpicker;

View File

@ -48,6 +48,8 @@ static void asset_view_item_but_drag_set(uiBut *but, AssetHandle *asset_handle)
blender::asset_system::AssetRepresentation *asset = ED_asset_handle_get_representation(
asset_handle);
UI_but_dragflag_enable(but, UI_BUT_DRAG_FULL_BUT);
ID *id = asset->local_id();
if (id != nullptr) {
UI_but_drag_set_id(but, id);

View File

@ -385,7 +385,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
* Ensure View2D rects remain in a viable configuration
* 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot'
*/
/* XXX pre2.5 -> this used to be called test_view2d() */
/* XXX pre2.5 -> this used to be called #test_view2d() */
static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize)
{
float totwidth, totheight, curwidth, curheight, width, height;

View File

@ -196,7 +196,7 @@ static void draw_parallel_lines(const ParallelLinesSet *lines,
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniform2fv("viewportSize", &viewport[2]);
/* -1.0f offset here is because the line is too fat due to the builtin anti-aliasing.
/* -1.0f offset here is because the line is too fat due to the builtin anti-aliasing.
* TODO: make a variant or a uniform to toggle it off. */
immUniform1f("lineWidth", U.pixelsize - 1.0f);
}

View File

@ -262,7 +262,7 @@ static bool edbm_inset_calc(wmOperator *op)
EDBM_op_init(em,
&bmop,
op,
"inset_individual faces=%hf use_even_offset=%b use_relative_offset=%b "
"inset_individual faces=%hf use_even_offset=%b use_relative_offset=%b "
"use_interpolate=%b thickness=%f depth=%f",
BM_ELEM_SELECT,
use_even_offset,

View File

@ -4210,9 +4210,9 @@ static float bm_edge_seg_isect(const float sco_a[2],
y2max = max_ff(y21, y22) + 0.001f;
y2min = min_ff(y21, y22) - 0.001f;
/* Found an intersect, calc intersect point */
if (m1 == m2) { /* co-incident lines */
/* cut at 50% of overlap area */
/* Found an intersect, calc intersect point. */
if (m1 == m2) { /* Co-incident lines. */
/* Cut at 50% of overlap area. */
x1max = max_ff(x11, x12);
x1min = min_ff(x11, x12);
xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f;

View File

@ -3683,8 +3683,8 @@ static int object_convert_exec(bContext *C, wmOperator *op)
}
}
// XXX ED_object_editmode_enter(C, 0);
// XXX exit_editmode(C, EM_FREEDATA|); /* free data, but no undo */
// XXX: ED_object_editmode_enter(C, 0);
// XXX: exit_editmode(C, EM_FREEDATA|); /* free data, but no undo. */
if (basact) {
/* active base was changed */

View File

@ -212,7 +212,7 @@ struct SlideOperationExecutor {
self_->initial_positions_cu_ = curves_orig_->positions();
self_->initial_deformed_positions_cu_ = deformation.positions;
/* First find all curves to slide. When the mouse moves, only those curves will be moved. */
/* First find all curves to slide. When the mouse moves, only those curves will be moved. */
this->find_curves_to_slide_with_symmetry();
return;
}

View File

@ -1065,14 +1065,14 @@ static void cursor_draw_tiling_preview(const uint gpuattr,
Object *ob,
const float radius)
{
const BoundBox *bb = BKE_object_boundbox_get(ob);
const BoundBox bb = *BKE_object_boundbox_get(ob);
float orgLoc[3], location[3];
int tile_pass = 0;
int start[3];
int end[3];
int cur[3];
const float *bbMin = bb->vec[0];
const float *bbMax = bb->vec[6];
const float *bbMin = bb.vec[0];
const float *bbMax = bb.vec[6];
const float *step = sd->paint.tile_offset;
copy_v3_v3(orgLoc, true_location);

View File

@ -198,17 +198,14 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
}
static void partialvis_update_bmesh_verts(BMesh *bm,
GSet *verts,
const blender::Set<BMVert *, 0> &verts,
PartialVisAction action,
PartialVisArea area,
float planes[4][4],
bool *any_changed,
bool *any_visible)
{
GSetIterator gs_iter;
GSET_ITER (gs_iter, verts) {
BMVert *v = static_cast<BMVert *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMVert *v : verts) {
float *vmask = static_cast<float *>(
CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK));
@ -229,13 +226,9 @@ static void partialvis_update_bmesh_verts(BMesh *bm,
}
}
static void partialvis_update_bmesh_faces(GSet *faces)
static void partialvis_update_bmesh_faces(const blender::Set<BMFace *, 0> &faces)
{
GSetIterator gs_iter;
GSET_ITER (gs_iter, faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : faces) {
if (paint_is_bmesh_face_hidden(f)) {
BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
}
@ -253,22 +246,25 @@ static void partialvis_update_bmesh(Object *ob,
float planes[4][4])
{
BMesh *bm;
GSet *unique, *other, *faces;
bool any_changed = false, any_visible = false;
bm = BKE_pbvh_get_bmesh(pbvh);
unique = BKE_pbvh_bmesh_node_unique_verts(node);
other = BKE_pbvh_bmesh_node_other_verts(node);
faces = BKE_pbvh_bmesh_node_faces(node);
SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
partialvis_update_bmesh_verts(bm, unique, action, area, planes, &any_changed, &any_visible);
partialvis_update_bmesh_verts(bm,
BKE_pbvh_bmesh_node_unique_verts(node),
action,
area,
planes,
&any_changed,
&any_visible);
partialvis_update_bmesh_verts(bm, other, action, area, planes, &any_changed, &any_visible);
partialvis_update_bmesh_verts(
bm, BKE_pbvh_bmesh_node_other_verts(node), action, area, planes, &any_changed, &any_visible);
/* Finally loop over node faces and tag the ones that are fully hidden. */
partialvis_update_bmesh_faces(faces);
partialvis_update_bmesh_faces(BKE_pbvh_bmesh_node_faces(node));
if (any_changed) {
BKE_pbvh_node_mark_rebuild_draw(node);

View File

@ -811,14 +811,14 @@ static blender::float3 paint_init_pivot_mesh(Object *ob)
static void paint_init_pivot_curves(Object *ob, float location[3])
{
const BoundBox *bbox = BKE_object_boundbox_get(ob);
interp_v3_v3v3(location, bbox->vec[0], bbox->vec[6], 0.5f);
const BoundBox bbox = *BKE_object_boundbox_get(ob);
interp_v3_v3v3(location, bbox.vec[0], bbox.vec[6], 0.5f);
}
static void paint_init_pivot_grease_pencil(Object *ob, float location[3])
{
const BoundBox *bbox = BKE_object_boundbox_get(ob);
interp_v3_v3v3(location, bbox->vec[0], bbox->vec[6], 0.5f);
const BoundBox bbox = *BKE_object_boundbox_get(ob);
interp_v3_v3v3(location, bbox.vec[0], bbox.vec[6], 0.5f);
}
void paint_init_pivot(Object *ob, Scene *scene)

View File

@ -829,10 +829,10 @@ static bool project_paint_PickColor(
/**
* Check if 'pt' is in front of the 3 verts on the Z axis (used for screen-space occlusion test)
* \return
* - `0`: no occlusion
* - `-1`: no occlusion but 2D intersection is true
* - `1`: occluded
* - `2`: occluded with `w[3]` weights set (need to know in some cases)
* - `0`: no occlusion.
* - `-1`: no occlusion but 2D intersection is true.
* - `1`: occluded.
* - `2`: occluded with `w[3]` weights set (need to know in some cases).
*/
static int project_paint_occlude_ptv(const float pt[3],
const float v1[4],

View File

@ -804,10 +804,9 @@ static Brush *brush_tool_cycle(Main *bmain, Paint *paint, Brush *brush_orig, con
}
}
else {
/* If user wants to switch to brush with the same tool as
/* If user wants to switch to brush with the same tool as
* currently active brush do a cycling via all possible
* brushes with requested tool.
*/
* brushes with requested tool. */
first_brush = brush_orig->id.next ? static_cast<Brush *>(brush_orig->id.next) :
static_cast<Brush *>(bmain->brushes.first);
}

View File

@ -4044,9 +4044,9 @@ static void do_tiled(Sculpt *sd,
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
const float radius = cache->radius;
const BoundBox *bb = BKE_object_boundbox_get(ob);
const float *bbMin = bb->vec[0];
const float *bbMax = bb->vec[6];
const BoundBox bb = *BKE_object_boundbox_get(ob);
const float *bbMin = bb.vec[0];
const float *bbMax = bb.vec[6];
const float *step = sd->paint.tile_offset;
/* These are integer locations, for real location: multiply with step and add orgLoc.

View File

@ -1514,15 +1514,12 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
break;
case SCULPT_UNDO_HIDDEN: {
GSetIterator gs_iter;
GSet *faces = BKE_pbvh_bmesh_node_faces(node);
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
}
BKE_pbvh_vertex_iter_end;
GSET_ITER (gs_iter, faces) {
BMFace *f = static_cast<BMFace *>(BLI_gsetIterator_getKey(&gs_iter));
for (BMFace *f : BKE_pbvh_bmesh_node_faces(node)) {
BM_log_face_modified(ss->bm_log, f);
}
break;

View File

@ -791,7 +791,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout,
* as metadata panel. So if the cache is skipped here it is not really a memory saver, but
* skipping the cache could lead to a performance impact depending on the order in which panels
* and the main area is drawn. Basically, if it is this template drawn first and then the main
* area it will lead to frame read and processing happening twice. */
* area it will lead to frame read and processing happening twice. */
ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, 0);
int width, height;

View File

@ -1297,7 +1297,7 @@ static int average_tracks_exec(bContext *C, wmOperator *op)
}
/* Create new empty track, which will be the averaged result.
* Makes it simple to average all selection to it. */
* Makes it simple to average all selection to it. */
MovieTrackingTrack *result_track = BKE_tracking_track_add_empty(tracking,
&tracking_object->tracks);

View File

@ -801,7 +801,7 @@ void uiTemplateImage(uiLayout *layout,
const float dpi_fac = UI_SCALE_FAC;
const int menus_width = 230 * dpi_fac;
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
/* Use #BKE_image_acquire_renderresult so we get the correct slot in the menu. */
rr = BKE_image_acquire_renderresult(scene, ima);
uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
BKE_image_release_renderresult(scene, ima);

View File

@ -336,12 +336,12 @@ static void gather_socket_link_operations(const bContext &C,
return true;
}
}
search_link_ops.append(
{std::string(IFACE_("Group Input")) + " " + UI_MENU_ARROW_SEP + interface_socket.name,
[interface_socket](nodes::LinkSearchOpParams &params) {
add_existing_group_input_fn(params, interface_socket);
},
weight});
search_link_ops.append({std::string(IFACE_("Group Input")) + " " + UI_MENU_ARROW_SEP +
(interface_socket.name ? interface_socket.name : ""),
[interface_socket](nodes::LinkSearchOpParams &params) {
add_existing_group_input_fn(params, interface_socket);
},
weight});
weight--;
return true;
});

View File

@ -1186,7 +1186,7 @@ static void node_socket_outline_color_get(const bool selected,
}
else if (socket_type == SOCK_CUSTOM) {
/* Until there is a better place for per socket color,
* the outline color for virtual sockets is set here. */
* the outline color for virtual sockets is set here. */
copy_v4_v4(r_outline_color, virtual_node_socket_outline_color);
}
else {
@ -2672,7 +2672,7 @@ static void node_draw_extra_info_panel_back(const bNode &node, const rctf &extra
{
const rctf &node_rect = node.runtime->totr;
rctf panel_back_rect = extra_info_rect;
/* Extend the panel behind hidden nodes to accomodate the large rounded corners. */
/* Extend the panel behind hidden nodes to accommodate the large rounded corners. */
if (node.flag & NODE_HIDDEN) {
panel_back_rect.ymin = BLI_rctf_cent_y(&node_rect);
}

View File

@ -96,7 +96,7 @@ struct SpaceNode_Runtime {
bool recalc_auto_compositing;
/**
* Indicates that the compositing int the space tree needs to be re-evaluated using
* Indicates that the compositing int the space tree needs to be re-evaluated using
* regular compositing pipeline.
*/
bool recalc_regular_compositing;

View File

@ -202,11 +202,10 @@ static bool retiming_key_add_new_for_seq(bContext *C,
const int timeline_frame)
{
Scene *scene = CTX_data_scene(C);
SEQ_retiming_data_ensure(seq);
const int frame_index = BKE_scene_frame_get(scene) - SEQ_time_start_frame_get(seq);
const SeqRetimingKey *key = SEQ_retiming_find_segment_start_key(seq, frame_index);
if (SEQ_retiming_key_is_transition_start(key)) {
if (key != nullptr && SEQ_retiming_key_is_transition_start(key)) {
BKE_report(op->reports, RPT_WARNING, "Can not create key inside of speed transition");
return false;
}
@ -216,6 +215,7 @@ static bool retiming_key_add_new_for_seq(bContext *C,
return false;
}
SEQ_retiming_data_ensure(seq);
SEQ_retiming_add_key(scene, seq, timeline_frame);
return true;
}

View File

@ -796,10 +796,9 @@ static void view3d_ob_drop_matrix_from_snap(V3DSnapCursorState *snap_state,
mat4_to_size(scale, ob->object_to_world);
rescale_m4(obmat_final, scale);
const BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
if (const std::optional<BoundBox> bb = BKE_object_boundbox_get(ob)) {
float offset[3];
BKE_boundbox_calc_center_aabb(bb, offset);
BKE_boundbox_calc_center_aabb(&bb.value(), offset);
offset[2] = bb->vec[0][2];
mul_mat3_m4_v3(obmat_final, offset);
sub_v3_v3(obmat_final[3], offset);

View File

@ -94,9 +94,10 @@ eV3DProjStatus ED_view3d_project_base(const ARegion *region, Base *base, float r
return ret;
}
/* perspmat is typically...
* - 'rv3d->perspmat', is_local == false
* - 'rv3d->persmatob', is_local == true
/**
* `perspmat` is typically either:
* - 'rv3d->perspmat', is_local == false.
* - 'rv3d->persmatob', is_local == true.
*/
static eV3DProjStatus ed_view3d_project__internal(const ARegion *region,
const float perspmat[4][4],

View File

@ -1958,7 +1958,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
*
* By definition transform-data has selected items in beginning,
* so only the first item in each container needs to be checked
* when looking for the presence of selected data. */
* when looking for the presence of selected data. */
if (t->flag & T_PROP_EDIT) {
bool has_selected_any = false;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {

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