Initial Grease Pencil 3.0 stage #106848

Merged
Falk David merged 224 commits from filedescriptor/blender:grease-pencil-v3 into main 2023-05-30 11:14:22 +02:00
32 changed files with 383 additions and 369 deletions
Showing only changes of commit 76565f700f - Show all commits

View File

@ -645,7 +645,7 @@ if(WITH_GHOST_WAYLAND)
else()
# Rocky8 packages have too old a version, a newer version exist in the pre-compiled libraries.
find_path(WAYLAND_PROTOCOLS_DIR
NAMES unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
NAMES staging/xdg-activation/xdg-activation-v1.xml
PATH_SUFFIXES share/wayland-protocols
PATHS ${LIBDIR}/wayland-protocols
)

View File

@ -590,11 +590,10 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
[mtlComputeCommandEncoder setThreadgroupMemoryLength:shared_mem_bytes atIndex:0];
}
MTLSize size_threadgroups_per_dispatch = MTLSizeMake(
divide_up(work_size, num_threads_per_block), 1, 1);
MTLSize size_threads_per_dispatch = MTLSizeMake(work_size, 1, 1);
MTLSize size_threads_per_threadgroup = MTLSizeMake(num_threads_per_block, 1, 1);
[mtlComputeCommandEncoder dispatchThreadgroups:size_threadgroups_per_dispatch
threadsPerThreadgroup:size_threads_per_threadgroup];
[mtlComputeCommandEncoder dispatchThreads:size_threads_per_dispatch
threadsPerThreadgroup:size_threads_per_threadgroup];
[mtlCommandBuffer_ addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
NSString *kernel_name = metal_kernel_pso->function.label;

View File

@ -91,6 +91,7 @@
#define ccl_gpu_kernel_postfix
#define ccl_gpu_kernel_call(x) x
#define ccl_gpu_kernel_within_bounds(i, n) ((i) < (n))
/* Define a function object where "func" is the lambda body, and additional parameters are used to
* specify captured state */

View File

@ -136,7 +136,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_closest(NULL, state, render_buffer));
}
@ -150,7 +150,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_shadow(NULL, state));
}
@ -164,7 +164,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_subsurface(NULL, state));
}
@ -178,7 +178,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_volume_stack(NULL, state));
}
@ -193,7 +193,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_shade_background(NULL, state, render_buffer));
}
@ -208,7 +208,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_shade_light(NULL, state, render_buffer));
}
@ -223,7 +223,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_shade_shadow(NULL, state, render_buffer));
}
@ -238,7 +238,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_shade_surface(NULL, state, render_buffer));
}
@ -257,7 +257,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
#if defined(__KERNEL_METAL_APPLE__) && defined(__METALRT__)
@ -281,7 +281,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_shade_surface_mnee(NULL, state, render_buffer));
}
@ -296,7 +296,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_shade_volume(NULL, state, render_buffer));
}
@ -492,7 +492,7 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int from_state = active_terminated_states[active_states_offset + global_index];
const int to_state = active_terminated_states[terminated_states_offset + global_index];
@ -526,7 +526,7 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
if (ccl_gpu_kernel_within_bounds(global_index, work_size)) {
const int from_state = active_terminated_states[active_states_offset + global_index];
const int to_state = active_terminated_states[terminated_states_offset + global_index];

View File

@ -34,6 +34,7 @@
#define ccl_gpu_kernel_postfix
#define ccl_gpu_kernel_call(x) x
#define ccl_gpu_kernel_within_bounds(i, n) ((i) < (n))
/* Define a function object where "func" is the lambda body, and additional parameters are used to
* specify captured state */

View File

@ -143,6 +143,7 @@ void kernel_gpu_##name::run(thread MetalKernelContext& context, \
#define ccl_gpu_kernel_postfix
#define ccl_gpu_kernel_call(x) context.x
#define ccl_gpu_kernel_within_bounds(i,n) true
/* define a function object where "func" is the lambda body, and additional parameters are used to specify captured state */
#define ccl_gpu_kernel_lambda(func, ...) \

View File

@ -289,9 +289,8 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
}
if (ray_tmax >= max_recorded_t) {
/* Accept hit, so that we don't consider any more hits beyond the distance of the
* current hit anymore. */
payload.result = true;
/* Ray hits are not guaranteed to be ordered by distance so don't exit early here.
* Continue search. */
return true;
}

View File

@ -101,6 +101,7 @@ void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \
#endif
#define ccl_gpu_kernel_call(x) ((ONEAPIKernelContext*)kg)->x
#define ccl_gpu_kernel_within_bounds(i, n) ((i) < (n))
#define ccl_gpu_kernel_lambda(func, ...) \
struct KernelLambda \

View File

@ -205,6 +205,14 @@ static bool use_gnome_confine_hack = false;
#define WL_NAME_UNSET uint32_t(-1)
/**
* Initializer for GHOST integer coordinates from `wl_fixed_t`,
* taking window scale into account.
*/
#define WL_FIXED_TO_INT_FOR_WINDOW_V2(win, xy) \
wl_fixed_to_int((win)->wl_fixed_to_window((xy)[0])), \
wl_fixed_to_int((win)->wl_fixed_to_window((xy)[1])),
/** \} */
/* -------------------------------------------------------------------- */
@ -1925,8 +1933,6 @@ static void relative_pointer_handle_relative_motion_impl(GWL_Seat *seat,
GHOST_WindowWayland *win,
const wl_fixed_t xy[2])
{
const wl_fixed_t scale = win->scale();
seat->pointer.xy[0] = xy[0];
seat->pointer.xy[1] = xy[1];
@ -1937,21 +1943,19 @@ static void relative_pointer_handle_relative_motion_impl(GWL_Seat *seat,
/* Needed or the cursor is considered outside the window and doesn't restore the location. */
bounds.m_r -= 1;
bounds.m_b -= 1;
bounds.m_l = wl_fixed_from_int(bounds.m_l) / scale;
bounds.m_t = wl_fixed_from_int(bounds.m_t) / scale;
bounds.m_r = wl_fixed_from_int(bounds.m_r) / scale;
bounds.m_b = wl_fixed_from_int(bounds.m_b) / scale;
bounds.m_l = win->wl_fixed_from_window(wl_fixed_from_int(bounds.m_l));
bounds.m_t = win->wl_fixed_from_window(wl_fixed_from_int(bounds.m_t));
bounds.m_r = win->wl_fixed_from_window(wl_fixed_from_int(bounds.m_r));
bounds.m_b = win->wl_fixed_from_window(wl_fixed_from_int(bounds.m_b));
bounds.clampPoint(UNPACK2(seat->pointer.xy));
}
#endif
seat->system->pushEvent_maybe_pending(
new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
wl_fixed_to_int(scale * seat->pointer.xy[0]),
wl_fixed_to_int(scale * seat->pointer.xy[1]),
GHOST_TABLET_DATA_NONE));
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, seat->pointer.xy)};
seat->system->pushEvent_maybe_pending(new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
UNPACK2(event_xy),
GHOST_TABLET_DATA_NONE));
}
static void relative_pointer_handle_relative_motion(
@ -1968,10 +1972,9 @@ static void relative_pointer_handle_relative_motion(
if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
CLOG_INFO(LOG, 2, "relative_motion");
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
const wl_fixed_t xy_next[2] = {
seat->pointer.xy[0] + (dx / scale),
seat->pointer.xy[1] + (dy / scale),
seat->pointer.xy[0] + win->wl_fixed_from_window(dx),
seat->pointer.xy[1] + win->wl_fixed_from_window(dy),
};
relative_pointer_handle_relative_motion_impl(seat, win, xy_next);
}
@ -2000,12 +2003,7 @@ static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event)
/* NOTE: `seat->data_offer_dnd_mutex` must already be locked. */
if (wl_surface *wl_surface_focus = seat->wl_surface_window_focus_dnd) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
const int event_xy[2] = {
wl_fixed_to_int(scale * seat->data_offer_dnd->dnd.xy[0]),
wl_fixed_to_int(scale * seat->data_offer_dnd->dnd.xy[1]),
};
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, seat->data_offer_dnd->dnd.xy)};
const uint64_t time = seat->system->getMilliSeconds();
for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_preference_order_type); i++) {
const GHOST_TDragnDropTypes type = ghost_wl_mime_preference_order_type[i];
@ -2477,13 +2475,12 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
}
CLOG_INFO(LOG, 2, "drop_read_uris_fn file_count=%d", flist->count);
const wl_fixed_t scale = win->scale();
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, xy)};
system->pushEvent_maybe_pending(new GHOST_EventDragnDrop(system->getMilliSeconds(),
GHOST_kEventDraggingDropDone,
GHOST_kDragnDropTypeFilenames,
win,
wl_fixed_to_int(scale * xy[0]),
wl_fixed_to_int(scale * xy[1]),
UNPACK2(event_xy),
flist));
}
else if (ELEM(mime_receive, ghost_wl_mime_text_plain, ghost_wl_mime_text_utf8)) {
@ -2685,14 +2682,12 @@ static void pointer_handle_enter(void *data,
seat->system->cursor_shape_set(win->getCursorShape());
const wl_fixed_t scale = win->scale();
seat->system->pushEvent_maybe_pending(
new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
wl_fixed_to_int(scale * seat->pointer.xy[0]),
wl_fixed_to_int(scale * seat->pointer.xy[1]),
GHOST_TABLET_DATA_NONE));
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, seat->pointer.xy)};
seat->system->pushEvent_maybe_pending(new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
UNPACK2(event_xy),
GHOST_TABLET_DATA_NONE));
}
static void pointer_handle_leave(void *data,
@ -2723,14 +2718,12 @@ static void pointer_handle_motion(void *data,
if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
CLOG_INFO(LOG, 2, "motion");
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
seat->system->pushEvent_maybe_pending(
new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
wl_fixed_to_int(scale * seat->pointer.xy[0]),
wl_fixed_to_int(scale * seat->pointer.xy[1]),
GHOST_TABLET_DATA_NONE));
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, seat->pointer.xy)};
seat->system->pushEvent_maybe_pending(new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
UNPACK2(event_xy),
GHOST_TABLET_DATA_NONE));
}
else {
CLOG_INFO(LOG, 2, "motion (skipped)");
@ -2849,13 +2842,12 @@ static void pointer_handle_frame(void *data, struct wl_pointer * /*wl_pointer*/)
if (seat->pointer_scroll.smooth_xy[0] || seat->pointer_scroll.smooth_xy[1]) {
if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, seat->pointer.xy)};
seat->system->pushEvent_maybe_pending(new GHOST_EventTrackpad(
seat->system->getMilliSeconds(),
win,
GHOST_kTrackpadEventScroll,
wl_fixed_to_int(scale * seat->pointer.xy[0]),
wl_fixed_to_int(scale * seat->pointer.xy[1]),
UNPACK2(event_xy),
/* NOTE: scaling the delta doesn't seem necessary.
* NOTE: inverting delta gives correct results, see: QTBUG-85767.
* NOTE: the preference to invert scrolling (in GNOME at least)
@ -3082,11 +3074,7 @@ static void gesture_pinch_handle_update(void *data,
&seat->pointer_gesture_pinch.rotation, rotation);
if (win) {
const wl_fixed_t win_scale = win->scale();
const int32_t event_xy[2] = {
wl_fixed_to_int(win_scale * seat->pointer.xy[0]),
wl_fixed_to_int(win_scale * seat->pointer.xy[1]),
};
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, seat->pointer.xy)};
if (scale_as_delta_px) {
seat->system->pushEvent_maybe_pending(
new GHOST_EventTrackpad(seat->system->getMilliSeconds(),
@ -3566,14 +3554,12 @@ static void tablet_tool_handle_frame(void *data,
/* No need to check the surfaces origin, it's already known to be owned by GHOST. */
if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
seat->system->pushEvent_maybe_pending(
new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
wl_fixed_to_int(scale * seat->tablet.xy[0]),
wl_fixed_to_int(scale * seat->tablet.xy[1]),
tablet_tool->data));
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, seat->tablet.xy)};
seat->system->pushEvent_maybe_pending(new GHOST_EventCursor(seat->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
UNPACK2(event_xy),
tablet_tool->data));
if (tablet_tool->proximity == false) {
seat->system->cursor_shape_set(win->getCursorShape());
}
@ -6020,7 +6006,6 @@ static GHOST_TSuccess getCursorPositionClientRelative_impl(
int32_t &x,
int32_t &y)
{
const wl_fixed_t scale = win->scale();
if (win->getCursorGrabModeIsWarp()) {
/* As the cursor is restored at the warped location,
@ -6037,18 +6022,19 @@ static GHOST_TSuccess getCursorPositionClientRelative_impl(
};
GHOST_Rect wrap_bounds_scale;
wrap_bounds_scale.m_l = wl_fixed_from_int(wrap_bounds.m_l) / scale;
wrap_bounds_scale.m_t = wl_fixed_from_int(wrap_bounds.m_t) / scale;
wrap_bounds_scale.m_r = wl_fixed_from_int(wrap_bounds.m_r) / scale;
wrap_bounds_scale.m_b = wl_fixed_from_int(wrap_bounds.m_b) / scale;
wrap_bounds_scale.m_l = win->wl_fixed_from_window(wl_fixed_from_int(wrap_bounds.m_l));
wrap_bounds_scale.m_t = win->wl_fixed_from_window(wl_fixed_from_int(wrap_bounds.m_t));
wrap_bounds_scale.m_r = win->wl_fixed_from_window(wl_fixed_from_int(wrap_bounds.m_r));
wrap_bounds_scale.m_b = win->wl_fixed_from_window(wl_fixed_from_int(wrap_bounds.m_b));
wrap_bounds_scale.wrapPoint(UNPACK2(xy_wrap), 0, win->getCursorGrabAxis());
x = wl_fixed_to_int(scale * xy_wrap[0]);
y = wl_fixed_to_int(scale * xy_wrap[1]);
x = wl_fixed_to_int(win->wl_fixed_to_window(xy_wrap[0]));
y = wl_fixed_to_int(win->wl_fixed_to_window(xy_wrap[1]));
}
else {
x = wl_fixed_to_int(scale * seat_state_pointer->xy[0]);
y = wl_fixed_to_int(scale * seat_state_pointer->xy[1]);
x = win->wl_fixed_to_window(seat_state_pointer->xy[0]);
y = win->wl_fixed_to_window(seat_state_pointer->xy[1]);
}
return GHOST_kSuccess;
@ -6065,10 +6051,9 @@ static GHOST_TSuccess setCursorPositionClientRelative_impl(GWL_Seat *seat,
if (!seat->wp_relative_pointer) {
return GHOST_kFailure;
}
const wl_fixed_t scale = win->scale();
const wl_fixed_t xy_next[2] = {
wl_fixed_from_int(x) / scale,
wl_fixed_from_int(y) / scale,
const wl_fixed_t xy_next[2]{
win->wl_fixed_from_window(wl_fixed_from_int(x)),
win->wl_fixed_from_window(wl_fixed_from_int(y)),
};
/* As the cursor was "warped" generate an event at the new location. */

View File

@ -87,6 +87,29 @@ static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
/** \name Internal #GWL_Window
* \{ */
#ifdef USE_EVENT_BACKGROUND_THREAD
enum eGWL_PendingWindowActions {
/**
* The state of the window frame has changed, apply the state from #GWL_Window::frame_pending.
*/
PENDING_WINDOW_FRAME_CONFIGURE = 0,
/** The EGL buffer must be resized to match #GWL_WindowFrame::size. */
PENDING_EGL_WINDOW_RESIZE,
# ifdef GHOST_OPENGL_ALPHA
/** Draw an opaque region behind the window. */
PENDING_OPAQUE_SET,
# endif
/**
* The DPI for a monitor has changed or the monitors (outputs)
* this window is visible on may have changed. Recalculate the windows scale.
*/
PENDING_OUTPUT_SCALE_UPDATE,
};
# define PENDING_NUM (PENDING_OUTPUT_SCALE_UPDATE + 1)
#endif /* USE_EVENT_BACKGROUND_THREAD */
struct GWL_WindowFrame {
int32_t size[2] = {0, 0};
bool is_maximised = false;
@ -148,7 +171,7 @@ struct GWL_Window {
* These pending actions can't be performed when WAYLAND handlers are running from a thread.
* Postpone their execution until the main thread can handle them.
*/
std::atomic<bool> pending_actions[3];
std::atomic<bool> pending_actions[PENDING_NUM];
#endif /* USE_EVENT_BACKGROUND_THREAD */
};
@ -366,25 +389,6 @@ static void gwl_window_frame_update_from_pending(GWL_Window *win);
#ifdef USE_EVENT_BACKGROUND_THREAD
enum eGWL_PendingWindowActions {
/**
* The state of the window frame has changed, apply the state from #GWL_Window::frame_pending.
*/
PENDING_WINDOW_FRAME_CONFIGURE = 0,
/** The EGL buffer must be resized to match #GWL_WindowFrame::size. */
PENDING_EGL_WINDOW_RESIZE,
# ifdef GHOST_OPENGL_ALPHA
/** Draw an opaque region behind the window. */
PENDING_OPAQUE_SET,
# endif
/**
* The DPI for a monitor has changed or the monitors (outputs)
* this window is visible on may have changed. Recalculate the windows scale.
*/
PENDING_OUTPUT_SCALE_UPDATE,
};
# define PENDING_NUM (PENDING_OUTPUT_SCALE_UPDATE + 1)
static void gwl_window_pending_actions_tag(GWL_Window *win, enum eGWL_PendingWindowActions type)
{
win->pending_actions[int(type)].store(true);
@ -1384,6 +1388,16 @@ wl_fixed_t GHOST_WindowWayland::scale_fractional() const
return window_->scale_fractional;
}
wl_fixed_t GHOST_WindowWayland::wl_fixed_from_window(wl_fixed_t value) const
{
return value / window_->scale;
}
wl_fixed_t GHOST_WindowWayland::wl_fixed_to_window(wl_fixed_t value) const
{
return value * window_->scale;
}
wl_surface *GHOST_WindowWayland::wl_surface() const
{
return window_->wl_surface;

View File

@ -144,6 +144,9 @@ class GHOST_WindowWayland : public GHOST_Window {
struct wl_surface *wl_surface() const;
const std::vector<GWL_Output *> &outputs();
wl_fixed_t wl_fixed_from_window(wl_fixed_t value) const;
wl_fixed_t wl_fixed_to_window(wl_fixed_t value) const;
/* WAYLAND window-level functions. */
GHOST_TSuccess close();

View File

@ -34,15 +34,17 @@ typedef struct BoxPack {
* There is no limit to the space boxes may take, only that they will be packed
* tightly into the lower left hand corner (0,0)
*
* \param boxarray: a pre-allocated array of boxes.
* \param box_array: a pre-allocated array of boxes.
* only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
* 'box->index' is not used at all, the only reason its there
* is that the box array is sorted by area and programs need to be able
* to have some way of writing the boxes back to the original data.
* \param len: the number of boxes in the array.
* \param sort_boxes: Sort `box_array` before packing.
* \param r_tot_x, r_tot_y: set so you can normalize the data.
*/
void BLI_box_pack_2d(BoxPack *boxarray, unsigned int len, float *r_tot_x, float *r_tot_y);
void BLI_box_pack_2d(
BoxPack *box_array, unsigned int len, bool sort_boxes, float *r_tot_x, float *r_tot_y);
typedef struct FixedSizeBoxPack {
struct FixedSizeBoxPack *next, *prev;

View File

@ -266,7 +266,8 @@ static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
/** \} */
void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r_tot_y)
void BLI_box_pack_2d(
BoxPack *boxarray, const uint len, const bool sort_boxes, float *r_tot_x, float *r_tot_y)
{
uint box_index, verts_pack_len, i, j, k;
uint *vertex_pack_indices; /* an array of indices used for sorting verts */
@ -284,8 +285,11 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
return;
}
/* Sort boxes, biggest first */
qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort);
if (sort_boxes) {
/* Sort boxes, biggest first.
* Be careful, qsort is not deterministic! */
qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort);
}
/* Add verts to the boxes, these are only used internally. */
vert = MEM_mallocN(sizeof(BoxVert[4]) * (size_t)len, "BoxPack Verts");

View File

@ -142,7 +142,7 @@ static bool get_channel_bounds(bAnimContext *ac,
/* Pad the given rctf with regions that could block the view.
* For example Markers and Time Scrubbing. */
static void add_region_padding(bContext *C, bAnimContext *ac, rctf *bounds)
static void add_region_padding(bContext *C, ARegion *region, rctf *bounds)
{
BLI_rctf_scale(bounds, 1.1f);
@ -150,9 +150,8 @@ static void add_region_padding(bContext *C, bAnimContext *ac, rctf *bounds)
const float pad_bottom = BLI_listbase_is_empty(ED_context_get_markers(C)) ?
V2D_SCROLL_HANDLE_HEIGHT :
UI_MARKER_MARGIN_Y;
BLI_rctf_pad_y(bounds, ac->region->winy, pad_bottom, pad_top);
BLI_rctf_pad_y(bounds, region->winy, pad_bottom, pad_top);
}
/** \} */
/* -------------------------------------------------------------------- */
@ -731,6 +730,45 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac,
anim_flush_channel_setting_down(ac, setting, mode, match, matchLevel);
}
void ANIM_frame_channel_y_extents(bContext *C, bAnimContext *ac)
{
ARegion *window_region = BKE_area_find_region_type(ac->area, RGN_TYPE_WINDOW);
if (!window_region) {
return;
}
ListBase anim_data = {NULL, NULL};
const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS |
ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
rctf bounds = {.xmin = FLT_MAX, .xmax = -FLT_MAX, .ymin = FLT_MAX, .ymax = -FLT_MAX};
const bool include_handles = false;
const float frame_range[2] = {window_region->v2d.cur.xmin, window_region->v2d.cur.xmax};
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
rctf channel_bounds;
const bool found_bounds = get_channel_bounds(
ac, ale, frame_range, include_handles, &channel_bounds);
if (found_bounds) {
BLI_rctf_union(&bounds, &channel_bounds);
}
}
if (!BLI_rctf_is_valid(&bounds)) {
ANIM_animdata_freelist(&anim_data);
return;
}
add_region_padding(C, window_region, &bounds);
window_region->v2d.cur.ymin = bounds.ymin;
window_region->v2d.cur.ymax = bounds.ymax;
ANIM_animdata_freelist(&anim_data);
}
/** \} */
/* -------------------------------------------------------------------- */
@ -3805,7 +3843,7 @@ static int graphkeys_view_selected_channels_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
add_region_padding(C, &ac, &bounds);
add_region_padding(C, window_region, &bounds);
if (ac.spacetype == SPACE_ACTION) {
bounds.ymin = window_region->v2d.cur.ymin;
@ -3893,7 +3931,7 @@ static int graphkeys_channel_view_pick_invoke(bContext *C, wmOperator *op, const
return OPERATOR_CANCELLED;
}
add_region_padding(C, &ac, &bounds);
add_region_padding(C, window_region, &bounds);
if (ac.spacetype == SPACE_ACTION) {
bounds.ymin = window_region->v2d.cur.ymin;

View File

@ -676,6 +676,8 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac,
eAnimChannel_Settings setting,
eAnimChannels_SetFlag mode);
void ANIM_frame_channel_y_extents(struct bContext *C, bAnimContext *ac);
/**
* Set selection state of all animation channels in the context.
*/

View File

@ -52,7 +52,8 @@ class CurvesEffect {
virtual ~CurvesEffect() = default;
virtual void execute(CurvesGeometry &curves,
Span<int> curve_indices,
Span<float> move_distances_cu) = 0;
Span<float> move_distances_cu,
MutableSpan<float3> positions_cu) = 0;
};
/**
@ -85,10 +86,10 @@ class ShrinkCurvesEffect : public CurvesEffect {
void execute(CurvesGeometry &curves,
const Span<int> curve_indices,
const Span<float> move_distances_cu) override
const Span<float> move_distances_cu,
MutableSpan<float3> positions_cu) override
{
const OffsetIndices points_by_curve = curves.points_by_curve();
MutableSpan<float3> positions_cu = curves.positions_for_write();
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
ParameterizationBuffers data;
for (const int influence_i : range) {
@ -135,10 +136,10 @@ class ShrinkCurvesEffect : public CurvesEffect {
class ExtrapolateCurvesEffect : public CurvesEffect {
void execute(CurvesGeometry &curves,
const Span<int> curve_indices,
const Span<float> move_distances_cu) override
const Span<float> move_distances_cu,
MutableSpan<float3> positions_cu) override
{
const OffsetIndices points_by_curve = curves.points_by_curve();
MutableSpan<float3> positions_cu = curves.positions_for_write();
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
MoveAndResampleBuffers resample_buffer;
for (const int influence_i : range) {
@ -175,10 +176,10 @@ class ScaleCurvesEffect : public CurvesEffect {
void execute(CurvesGeometry &curves,
const Span<int> curve_indices,
const Span<float> move_distances_cu) override
const Span<float> move_distances_cu,
MutableSpan<float3> positions_cu) override
{
const OffsetIndices points_by_curve = curves.points_by_curve();
MutableSpan<float3> positions_cu = curves.positions_for_write();
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
for (const int influence_i : range) {
const int curve_i = curve_indices[influence_i];
@ -322,9 +323,11 @@ struct CurvesEffectOperationExecutor {
}
/* Execute effect. */
MutableSpan<float3> positions_cu = curves_->positions_for_write();
threading::parallel_for_each(influences_for_thread, [&](const Influences &influences) {
BLI_assert(influences.curve_indices.size() == influences.move_distances_cu.size());
self_->effect_->execute(*curves_, influences.curve_indices, influences.move_distances_cu);
self_->effect_->execute(
*curves_, influences.curve_indices, influences.move_distances_cu, positions_cu);
});
curves_->tag_positions_changed();

View File

@ -88,6 +88,7 @@ class PackIsland {
void finalize_geometry(const UVPackIsland_Params &params, MemArena *arena, Heap *heap);
private:
void calculate_pivot(); /* Choose a pivot based on triangles. */
blender::Vector<float2> triangle_vertices_;
friend class Occupancy;
};

View File

@ -131,7 +131,8 @@ void PackIsland::finalize_geometry(const UVPackIsland_Params &params, MemArena *
if (shape_method == ED_UVPACK_SHAPE_CONVEX) {
/* Compute convex hull of existing triangles. */
if (triangle_vertices_.size() <= 3) {
return; /* Trivial case, nothing to do. */
calculate_pivot();
return; /* Trivial case, calculate pivot only. */
}
int vert_count = int(triangle_vertices_.size());
@ -156,7 +157,11 @@ void PackIsland::finalize_geometry(const UVPackIsland_Params &params, MemArena *
BLI_heap_clear(heap, nullptr);
}
calculate_pivot();
}
void PackIsland::calculate_pivot()
{
Bounds<float2> triangle_bounds = *bounds::min_max(triangle_vertices_.as_span());
float2 aabb_min = triangle_bounds.min;
float2 aabb_max = triangle_bounds.max;
@ -821,7 +826,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
&max_v);
break;
default:
BLI_box_pack_2d(box_array, int(max_box_pack), &max_u, &max_v);
BLI_box_pack_2d(box_array, int(max_box_pack), false, &max_u, &max_v);
break;
}

View File

@ -1013,15 +1013,14 @@ static PChart **p_split_charts(ParamHandle *handle, PChart *chart, int ncharts)
static PFace *p_face_add(ParamHandle *handle)
{
PFace *f;
PEdge *e1, *e2, *e3;
/* allocate */
f = (PFace *)BLI_memarena_alloc(handle->arena, sizeof(*f));
f->flag = 0; /* init ! */
e1 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e1));
e2 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e2));
e3 = (PEdge *)BLI_memarena_alloc(handle->arena, sizeof(*e3));
PEdge *e1 = (PEdge *)BLI_memarena_calloc(handle->arena, sizeof(*e1));
PEdge *e2 = (PEdge *)BLI_memarena_calloc(handle->arena, sizeof(*e2));
PEdge *e3 = (PEdge *)BLI_memarena_calloc(handle->arena, sizeof(*e3));
/* set up edges */
f->edge = e1;
@ -1031,14 +1030,6 @@ static PFace *p_face_add(ParamHandle *handle)
e2->next = e3;
e3->next = e1;
e1->pair = nullptr;
e2->pair = nullptr;
e3->pair = nullptr;
e1->flag = 0;
e2->flag = 0;
e3->flag = 0;
return f;
}

View File

@ -9,7 +9,9 @@
#include "DNA_collection_types.h"
#include "DNA_scene_types.h"
#include "BKE_context.h"
#include "BLI_memory_utils.hh"
#include "IO_ply.h"
#include "ply_data.hh"
#include "ply_export.hh"

View File

@ -6,20 +6,12 @@
#pragma once
#include "IO_ply.h"
#include "ply_data.hh"
#include "ply_file_buffer.hh"
struct bContext;
struct PLYExportParams;
namespace blender::io::ply {
/* Main export function used from within Blender. */
void exporter_main(bContext *C, const PLYExportParams &export_params);
/* Used from tests, where full bContext does not exist. */
void exporter_main(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
bContext *C,
const PLYExportParams &export_params);
} // namespace blender::io::ply

View File

@ -6,11 +6,11 @@
#pragma once
#include "ply_data.hh"
#include "ply_file_buffer.hh"
namespace blender::io::ply {
class FileBuffer;
struct PlyData;
void write_vertices(FileBuffer &buffer, const PlyData &ply_data);
void write_faces(FileBuffer &buffer, const PlyData &ply_data);

View File

@ -5,7 +5,6 @@
*/
#include "BKE_blender_version.h"
#include "BKE_customdata.h"
#include "IO_ply.h"
#include "ply_data.hh"

View File

@ -6,11 +6,13 @@
#pragma once
#include "ply_data.hh"
#include "ply_file_buffer.hh"
struct PLYExportParams;
namespace blender::io::ply {
class FileBuffer;
struct PlyData;
void write_header(FileBuffer &buffer,
const PlyData &ply_data,
const PLYExportParams &export_params);

View File

@ -4,38 +4,27 @@
* \ingroup ply
*/
#include "BLI_array.hh"
#include "BLI_math.h"
#include "ply_export_load_plydata.hh"
#include "IO_ply.h"
#include "ply_data.hh"
#include "BKE_attribute.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "BLI_hash.hh"
#include "BLI_math.h"
#include "BLI_vector.hh"
#include "DEG_depsgraph_query.h"
#include "DNA_layer_types.h"
#include "IO_ply.h"
#include "bmesh.h"
#include "bmesh_tools.h"
#include <tools/bmesh_triangulate.h>
#include "ply_data.hh"
#include "ply_export_load_plydata.hh"
namespace blender::io::ply {
float world_and_axes_transform_[4][4];
float world_and_axes_normal_transform_[3][3];
bool mirrored_transform_;
Mesh *do_triangulation(const Mesh *mesh, bool force_triangulation)
static Mesh *do_triangulation(const Mesh *mesh, bool force_triangulation)
{
const BMeshCreateParams bm_create_params = {false};
BMeshFromMeshParams bm_convert_params{};
@ -50,28 +39,110 @@ Mesh *do_triangulation(const Mesh *mesh, bool force_triangulation)
return temp_mesh;
}
void set_world_axes_transform(Object *object, const eIOAxis forward, const eIOAxis up)
static void set_world_axes_transform(Object *object,
const eIOAxis forward,
const eIOAxis up,
float r_world_and_axes_transform[4][4],
float r_world_and_axes_normal_transform[3][3])
{
float axes_transform[3][3];
unit_m3(axes_transform);
/* +Y-forward and +Z-up are the default Blender axis settings. */
mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
mul_m4_m3m4(world_and_axes_transform_, axes_transform, object->object_to_world);
mul_m4_m3m4(r_world_and_axes_transform, axes_transform, object->object_to_world);
/* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, object->object_to_world[3]);
world_and_axes_transform_[3][3] = object->object_to_world[3][3];
mul_v3_m3v3(r_world_and_axes_transform[3], axes_transform, object->object_to_world[3]);
r_world_and_axes_transform[3][3] = object->object_to_world[3][3];
/* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */
float normal_matrix[3][3];
copy_m3_m4(normal_matrix, world_and_axes_transform_);
invert_m3_m3(world_and_axes_normal_transform_, normal_matrix);
transpose_m3(world_and_axes_normal_transform_);
mirrored_transform_ = is_negative_m3(world_and_axes_normal_transform_);
copy_m3_m4(normal_matrix, r_world_and_axes_transform);
invert_m3_m3(r_world_and_axes_normal_transform, normal_matrix);
transpose_m3(r_world_and_axes_normal_transform);
}
struct uv_vertex_key {
float2 uv;
int vertex_index;
bool operator==(const uv_vertex_key &r) const
{
return (uv == r.uv && vertex_index == r.vertex_index);
}
uint64_t hash() const
{
return get_default_hash_3(uv.x, uv.y, vertex_index);
}
};
static void generate_vertex_map(const Mesh *mesh,
const PLYExportParams &export_params,
Vector<int> &r_ply_to_vertex,
Vector<int> &r_vertex_to_ply,
Vector<int> &r_loop_to_ply,
Vector<float2> &r_uvs)
{
bool export_uv = false;
VArraySpan<float2> uv_map;
if (export_params.export_uv) {
const StringRef uv_name = CustomData_get_active_layer_name(&mesh->ldata, CD_PROP_FLOAT2);
if (!uv_name.is_empty()) {
const bke::AttributeAccessor attributes = mesh->attributes();
uv_map = attributes.lookup<float2>(uv_name, ATTR_DOMAIN_CORNER);
export_uv = !uv_map.is_empty();
}
}
const Span<int> corner_verts = mesh->corner_verts();
r_vertex_to_ply.resize(mesh->totvert, -1);
r_loop_to_ply.resize(mesh->totloop, -1);
/* If we do not export or have UVs, then mapping of vertex indices is simple. */
if (!export_uv) {
r_ply_to_vertex.resize(mesh->totvert);
for (int index = 0; index < mesh->totvert; index++) {
r_vertex_to_ply[index] = index;
r_ply_to_vertex[index] = index;
}
for (int index = 0; index < mesh->totloop; index++) {
r_loop_to_ply[index] = corner_verts[index];
}
return;
}
/* We are exporting UVs. Need to build mappings of what
* any unique (vertex, UV) values will map into the PLY data. */
Map<uv_vertex_key, int> vertex_map;
vertex_map.reserve(mesh->totvert);
r_ply_to_vertex.reserve(mesh->totvert);
r_uvs.reserve(mesh->totvert);
for (int loop_index = 0; loop_index < int(corner_verts.size()); loop_index++) {
int vertex_index = corner_verts[loop_index];
uv_vertex_key key{uv_map[loop_index], vertex_index};
int ply_index = vertex_map.lookup_or_add(key, int(vertex_map.size()));
r_vertex_to_ply[vertex_index] = ply_index;
r_loop_to_ply[loop_index] = ply_index;
while (r_uvs.size() <= ply_index) {
r_uvs.append(key.uv);
r_ply_to_vertex.append(key.vertex_index);
}
}
/* Add zero UVs for any loose vertices. */
for (int vertex_index = 0; vertex_index < mesh->totvert; vertex_index++) {
if (r_vertex_to_ply[vertex_index] != -1)
continue;
int ply_index = int(r_uvs.size());
r_vertex_to_ply[vertex_index] = ply_index;
r_uvs.append({0, 0});
r_ply_to_vertex.append(vertex_index);
}
}
void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams &export_params)
{
DEGObjectIterSettings deg_iter_settings{};
deg_iter_settings.depsgraph = depsgraph;
deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
@ -111,73 +182,56 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
manually_free_mesh = true;
}
const float2 *uv_map = static_cast<const float2 *>(
CustomData_get_layer(&mesh->ldata, CD_PROP_FLOAT2));
Vector<int> ply_to_vertex, vertex_to_ply, loop_to_ply;
Vector<float2> uvs;
generate_vertex_map(mesh, export_params, ply_to_vertex, vertex_to_ply, loop_to_ply, uvs);
Map<UV_vertex_key, int> vertex_map;
generate_vertex_map(mesh, uv_map, export_params, vertex_map);
float world_and_axes_transform[4][4];
float world_and_axes_normal_transform[3][3];
set_world_axes_transform(&export_object_eval_,
export_params.forward_axis,
export_params.up_axis,
world_and_axes_transform,
world_and_axes_normal_transform);
set_world_axes_transform(
&export_object_eval_, export_params.forward_axis, export_params.up_axis);
/* Load faces into plyData. */
/* Face data. */
plyData.face_vertices.reserve(mesh->totloop);
plyData.face_sizes.reserve(mesh->totpoly);
int loop_offset = 0;
const Span<int> corner_verts = mesh->corner_verts();
for (const MPoly &poly : mesh->polys()) {
const Span<int> mesh_poly_verts = corner_verts.slice(poly.loopstart, poly.totloop);
Array<uint32_t> poly_verts(mesh_poly_verts.size());
for (int i = 0; i < mesh_poly_verts.size(); ++i) {
float2 uv;
if (export_params.export_uv && uv_map != nullptr) {
uv = uv_map[i + loop_offset];
}
else {
uv = {0, 0};
}
UV_vertex_key key = UV_vertex_key(uv, mesh_poly_verts[i]);
int ply_vertex_index = vertex_map.lookup(key);
plyData.face_vertices.append(ply_vertex_index + vertex_offset);
for (int i = 0; i < poly.totloop; ++i) {
int ply_index = loop_to_ply[i + loop_offset];
BLI_assert(ply_index >= 0 && ply_index < ply_to_vertex.size());
plyData.face_vertices.append(ply_index + vertex_offset);
}
loop_offset += poly.totloop;
plyData.face_sizes.append(poly.totloop);
}
Array<int> mesh_vertex_index_LUT(vertex_map.size());
Array<int> ply_vertex_index_LUT(mesh->totvert);
Array<float2> uv_coordinates(vertex_map.size());
for (auto const &[key, ply_vertex_index] : vertex_map.items()) {
mesh_vertex_index_LUT[ply_vertex_index] = key.mesh_vertex_index;
ply_vertex_index_LUT[key.mesh_vertex_index] = ply_vertex_index;
uv_coordinates[ply_vertex_index] = key.UV;
}
/* Vertices */
for (int i = 0; i < vertex_map.size(); ++i) {
float3 r_coords;
copy_v3_v3(r_coords, mesh->vert_positions()[mesh_vertex_index_LUT[i]]);
mul_m4_v3(world_and_axes_transform_, r_coords);
mul_v3_fl(r_coords, export_params.global_scale);
plyData.vertices.append(r_coords);
plyData.vertices.reserve(ply_to_vertex.size());
Span<float3> vert_positions = mesh->vert_positions();
for (int vertex_index : ply_to_vertex) {
float3 pos = vert_positions[vertex_index];
mul_m4_v3(world_and_axes_transform, pos);
mul_v3_fl(pos, export_params.global_scale);
plyData.vertices.append(pos);
}
/* UV's */
if (export_params.export_uv) {
for (int i = 0; i < vertex_map.size(); ++i) {
plyData.uv_coordinates.append(uv_coordinates[i]);
}
if (!uvs.is_empty()) {
BLI_assert(uvs.size() == ply_to_vertex.size());
plyData.uv_coordinates = uvs;
}
/* Normals */
if (export_params.export_normals) {
plyData.vertex_normals.reserve(ply_to_vertex.size());
const Span<float3> vert_normals = mesh->vert_normals();
for (int i = 0; i < vertex_map.size(); i++) {
mul_m3_v3(world_and_axes_normal_transform_,
float3(vert_normals[mesh_vertex_index_LUT[i]]));
plyData.vertex_normals.append(vert_normals[mesh_vertex_index_LUT[i]]);
for (int vertex_index : ply_to_vertex) {
float3 normal = vert_normals[vertex_index];
mul_m3_v3(world_and_axes_normal_transform, normal);
plyData.vertex_normals.append(normal);
}
}
@ -189,27 +243,28 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
const VArray<ColorGeometry4f> color_attribute =
attributes.lookup_or_default<ColorGeometry4f>(
name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
for (int i = 0; i < vertex_map.size(); i++) {
ColorGeometry4f colorGeometry = color_attribute[mesh_vertex_index_LUT[i]];
float4 vertColor(colorGeometry.r, colorGeometry.g, colorGeometry.b, colorGeometry.a);
if (export_params.vertex_colors == PLY_VERTEX_COLOR_SRGB) {
linearrgb_to_srgb_v4(vertColor, vertColor);
if (!color_attribute.is_empty()) {
plyData.vertex_colors.reserve(ply_to_vertex.size());
for (int vertex_index : ply_to_vertex) {
float4 color = float4(color_attribute[vertex_index]);
if (export_params.vertex_colors == PLY_VERTEX_COLOR_SRGB) {
linearrgb_to_srgb_v4(color, color);
}
plyData.vertex_colors.append(color);
}
plyData.vertex_colors.append(vertColor);
}
}
}
/* Edges */
/* Loose edges */
const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
if (loose_edges.count > 0) {
Span<MEdge> edges = mesh->edges();
for (int i = 0; i < edges.size(); ++i) {
if (loose_edges.is_loose_bits[i]) {
int index_one = ply_vertex_index_LUT[edges[i].v1];
int index_two = ply_vertex_index_LUT[edges[i].v2];
plyData.edges.append({index_one, index_two});
int v1 = vertex_to_ply[edges[i].v1];
int v2 = vertex_to_ply[edges[i].v2];
plyData.edges.append({v1, v2});
}
}
}
@ -223,55 +278,4 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
DEG_OBJECT_ITER_END;
}
void generate_vertex_map(const Mesh *mesh,
const float2 *uv_map,
const PLYExportParams &export_params,
Map<UV_vertex_key, int> &r_map)
{
const Span<MPoly> polys = mesh->polys();
const Span<int> corner_verts = mesh->corner_verts();
const int totvert = mesh->totvert;
r_map.reserve(totvert);
if (uv_map == nullptr || !export_params.export_uv) {
for (int vertex_index = 0; vertex_index < totvert; ++vertex_index) {
UV_vertex_key key = UV_vertex_key({0, 0}, vertex_index);
r_map.add_new(key, int(r_map.size()));
}
return;
}
const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(polys.data(),
nullptr,
nullptr,
corner_verts.data(),
reinterpret_cast<const float(*)[2]>(uv_map),
uint(polys.size()),
totvert,
limit,
false,
false);
for (int vertex_index = 0; vertex_index < totvert; vertex_index++) {
const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
if (uv_vert == nullptr) {
UV_vertex_key key = UV_vertex_key({0, 0}, vertex_index);
r_map.add_new(key, int(r_map.size()));
}
for (; uv_vert; uv_vert = uv_vert->next) {
/* Store UV vertex coordinates. */
const int loopstart = polys[uv_vert->poly_index].loopstart;
float2 vert_uv_coords(uv_map[loopstart + uv_vert->loop_of_poly_index]);
UV_vertex_key key = UV_vertex_key(vert_uv_coords, vertex_index);
r_map.add(key, int(r_map.size()));
}
}
BKE_mesh_uv_vert_map_free(uv_vert_map);
}
} // namespace blender::io::ply

View File

@ -6,52 +6,13 @@
#pragma once
#include "BKE_mesh.h"
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
#include "BLI_hash.hh"
#include "BLI_math.h"
#include "RNA_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "DNA_layer_types.h"
#include "ply_data.hh"
struct Depsgraph;
struct PLYExportParams;
namespace blender::io::ply {
Mesh *do_triangulation(const Mesh *mesh, bool force_triangulation);
void set_world_axes_transform(Object *object, const eIOAxis forward, const eIOAxis up);
struct UV_vertex_key {
float2 UV;
int mesh_vertex_index;
UV_vertex_key(float2 UV, int vertex_index) : UV(UV), mesh_vertex_index(vertex_index) {}
bool operator==(const UV_vertex_key &r) const
{
return (UV == r.UV && mesh_vertex_index == r.mesh_vertex_index);
}
uint64_t hash() const
{
return get_default_hash_3(UV.x, UV.y, mesh_vertex_index);
}
};
void generate_vertex_map(const Mesh *mesh,
const float2 *uv_map,
const PLYExportParams &export_params,
Map<UV_vertex_key, int> &r_map);
struct PlyData;
void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams &export_params);
} // namespace blender::io::ply

View File

@ -6,6 +6,8 @@
#include "ply_file_buffer_binary.hh"
#include "BLI_math_vector_types.hh"
namespace blender::io::ply {
void FileBufferBinary::write_vertex(float x, float y, float z)
{

View File

@ -6,20 +6,8 @@
#pragma once
#include <string>
#include <type_traits>
#include "BLI_array.hh"
#include "BLI_compiler_attrs.h"
#include "BLI_fileops.h"
#include "BLI_math_vector_types.hh"
#include "BLI_string_ref.hh"
#include "BLI_utility_mixins.hh"
#include "ply_file_buffer.hh"
#include <bitset>
namespace blender::io::ply {
class FileBufferBinary : public FileBuffer {
using FileBuffer::FileBuffer;

View File

@ -6,7 +6,6 @@
#pragma once
#include "BLI_array.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_vector.hh"

View File

@ -484,30 +484,30 @@ TEST_F(ply_exporter_ply_data_test, CubeLooseEdgesLoadPLYDataUV)
PlyData plyData = load_ply_data_from_blendfile(
"io_tests/blend_geometry/cube_loose_edges_verts.blend", params);
float3 exp_vertices[] = {
{1, 1, 1},
{-1, 1, -1},
{1, 1, -1},
{1, -1, 1},
{1, -1, -1},
{-1, 1, 1},
{-1, 1, -1},
{-1, 1, -1},
{-1, -1, 1},
{-1, -1, -1},
{-1, 1, -1},
{-1, 1, 1},
{1, 1, 1},
{1, -1, 1},
{-1, -1, 1},
};
float2 exp_uv[] = {
{0.625f, 0.5f},
{0.375f, 0.5f},
{0, 0},
{0.375f, 0.75f},
{0.625f, 0.25f},
{0.125f, 0.5f},
{0.375f, 0.25f},
{0, 0},
{0.375f, 0.5f},
{0.375f, 0.75f},
{0.125f, 0.75f},
{0.375f, 0.25f},
{0.625f, 0.25f},
{0.625f, 0.5f},
{0, 0},
{0, 0},
};
std::pair<int, int> exp_edges[] = {{8, 7}, {7, 4}};
std::pair<int, int> exp_edges[] = {{3, 8}, {8, 5}};
uint32_t exp_face_sizes[] = {4, 4};
uint32_t exp_faces[] = {5, 1, 3, 8, 6, 4, 0, 1};
uint32_t exp_faces[] = {0, 1, 2, 3, 4, 5, 6, 1};
EXPECT_EQ(plyData.vertices.size(), 9);
EXPECT_EQ(plyData.uv_coordinates.size(), 9);
EXPECT_EQ(plyData.edges.size(), ARRAY_SIZE(exp_edges));

View File

@ -2376,6 +2376,18 @@ static void rna_SpaceGraphEditor_display_mode_update(bContext *C, PointerRNA *pt
ED_area_tag_refresh(area);
}
static void rna_SpaceGraphEditor_normalize_update(bContext *C, PointerRNA *UNUSED(ptr))
{
bAnimContext ac;
if (ANIM_animdata_get_context(C, &ac) == 0) {
return;
}
ANIM_frame_channel_y_extents(C, &ac);
ED_area_tag_refresh(ac.area);
}
static bool rna_SpaceGraphEditor_has_ghost_curves_get(PointerRNA *ptr)
{
SpaceGraph *sipo = (SpaceGraph *)(ptr->data);
@ -6414,7 +6426,9 @@ static void rna_def_space_graph(BlenderRNA *brna)
"Use Normalization",
"Display curves in normalized range from -1 to 1, "
"for easier editing of multiple curves with different ranges");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(
prop, NC_SPACE | ND_SPACE_GRAPH, "rna_SpaceGraphEditor_normalize_update");
prop = RNA_def_property(srna, "use_auto_normalization", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NORMALIZE_FREEZE);

View File

@ -1404,8 +1404,9 @@ static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlis
return NULL; /* exception set */
}
const bool sort_boxes = true; /* Caution: BLI_box_pack_2d sorting is non-deterministic. */
/* Non Python function */
BLI_box_pack_2d(boxarray, len, &tot_width, &tot_height);
BLI_box_pack_2d(boxarray, len, sort_boxes, &tot_width, &tot_height);
boxPack_ToPyObject(boxlist, boxarray);
MEM_freeN(boxarray);