Mesh: Replace auto smooth with node group #108014
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*/,
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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");
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)++;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_);
|
||||
|
|
|
@ -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)");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ¶ms) {
|
||||
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 ¶ms) {
|
||||
add_existing_group_input_fn(params, interface_socket);
|
||||
},
|
||||
weight});
|
||||
weight--;
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue