Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmar Emara <mail@OmarEmara.dev>2022-06-15 15:35:44 +0300
committerOmar Emara <mail@OmarEmara.dev>2022-06-15 15:35:44 +0300
commit082c87bf9624e888edc40c27a9b9fcaea32a6195 (patch)
treec6d67d8a5c4fdcca7ee34a61329f58483a8eb8e5
parent034cea15470ac161f9f5d047c07bb7fb22980e3d (diff)
parent2e6cd7047397b0724b5fbafa775d0b02bfd0c329 (diff)
Merge branch 'master' into temp-viewport-compositor-merge
-rw-r--r--intern/ghost/CMakeLists.txt9
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp1073
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h35
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp178
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.h3
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_density.dat (renamed from release/datafiles/icons/ops.curves.density.dat)bin3032 -> 3032 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_slide.dat (renamed from release/datafiles/icons/ops.curves.slide.dat)bin1394 -> 1394 bytes
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py12
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py3
-rw-r--r--source/blender/blenkernel/BKE_attribute.h4
-rw-r--r--source/blender/blenkernel/BKE_subdiv_modifier.h36
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc33
-rw-r--r--source/blender/blenkernel/intern/attribute.cc55
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.cc23
-rw-r--r--source/blender/blenkernel/intern/nla.c45
-rw-r--r--source/blender/blenkernel/intern/pbvh.c16
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c62
-rw-r--r--source/blender/blenkernel/intern/tracking.c8
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc6
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.cc3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc50
-rw-r--r--source/blender/draw/intern/draw_subdivision.h3
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc147
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt4
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc13
-rw-r--r--source/blender/editors/interface/interface_handlers.c3
-rw-r--r--source/blender/editors/interface/interface_ops.c20
-rw-r--r--source/blender/editors/io/io_obj.c3
-rw-r--r--source/blender/editors/mask/mask_select.c9
-rw-r--r--source/blender/editors/space_clip/tracking_select.c2
-rw-r--r--source/blender/editors/space_info/info_stats.cc18
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc24
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c20
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c287
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc4
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator.cc5
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.cc56
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.hh14
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h1
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc37
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh5
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc2
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc58
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.cc24
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.hh1
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_objects.hh3
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc17
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh1
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_importer_tests.cc122
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h19
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h7
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc2
-rw-r--r--source/blender/sequencer/SEQ_transform.h2
-rw-r--r--source/blender/sequencer/intern/strip_transform.c299
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c14
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c5
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c4
-rwxr-xr-xtests/python/modules/render_report.py8
64 files changed, 1760 insertions, 1218 deletions
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 0a6e19f006c..5b06b5d98e6 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -324,16 +324,21 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
${CMAKE_CURRENT_BINARY_DIR}
)
- # xdg-shell.
+ # `xdg-shell`.
generate_protocol_bindings(
xdg-shell
"${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml"
)
- # xdg-decoration.
+ # `xdg-decoration`.
generate_protocol_bindings(
xdg-decoration
"${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
)
+ # `xdg-output`.
+ generate_protocol_bindings(
+ xdg-output
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-output/xdg-output-unstable-v1.xml"
+ )
# Pointer-constraints.
generate_protocol_bindings(
pointer-constraints
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 9e683ceb437..b59adef1724 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -31,6 +31,8 @@
#include <relative-pointer-client-protocol.h>
#include <tablet-client-protocol.h>
#include <wayland-cursor.h>
+#include <xdg-output-client-protocol.h>
+
#include <xkbcommon/xkbcommon.h>
#include <fcntl.h>
@@ -40,7 +42,7 @@
#include <cstring>
#include <mutex>
-static GHOST_IWindow *get_window(struct wl_surface *surface);
+static GHOST_WindowWayland *window_from_surface(struct wl_surface *surface);
/* -------------------------------------------------------------------- */
/** \name Private Types & Defines
@@ -70,18 +72,18 @@ static GHOST_IWindow *get_window(struct wl_surface *surface);
#define BTN_STYLUS3 0x149
struct buffer_t {
- void *data;
- size_t size;
+ void *data = nullptr;
+ size_t size = 0;
};
struct cursor_t {
- bool visible;
- struct wl_surface *surface = nullptr;
- struct wl_buffer *buffer;
- struct wl_cursor_image image;
+ bool visible = false;
+ struct wl_surface *wl_surface = nullptr;
+ struct wl_buffer *wl_buffer = nullptr;
+ struct wl_cursor_image wl_image = {0};
+ struct wl_cursor_theme *wl_theme = nullptr;
struct buffer_t *file_buffer = nullptr;
- struct wl_cursor_theme *theme = nullptr;
- int size;
+ int size = 0;
std::string theme_name;
/** Outputs on which the cursor is visible. */
std::unordered_set<const output_t *> outputs;
@@ -94,53 +96,52 @@ struct cursor_t {
* Since are no API's to access properties of the tool, store the values here.
*/
struct tablet_tool_input_t {
- struct input_t *input;
- struct wl_surface *cursor_surface;
+ struct input_t *input = nullptr;
+ struct wl_surface *cursor_surface = nullptr;
- GHOST_TabletData data;
+ GHOST_TabletData data = GHOST_TABLET_DATA_NONE;
};
struct data_offer_t {
std::unordered_set<std::string> types;
- uint32_t source_actions;
- uint32_t dnd_action;
- struct wl_data_offer *id;
- std::atomic<bool> in_use;
+ uint32_t source_actions = 0;
+ uint32_t dnd_action = 0;
+ struct wl_data_offer *id = nullptr;
+ std::atomic<bool> in_use = false;
struct {
/** Compatible with #input_t.xy coordinates. */
- wl_fixed_t xy[2];
+ wl_fixed_t xy[2] = {0, 0};
} dnd;
};
struct data_source_t {
- struct wl_data_source *data_source;
- char *buffer_out;
+ struct wl_data_source *data_source = nullptr;
+ char *buffer_out = nullptr;
};
struct key_repeat_payload_t {
- GHOST_SystemWayland *system;
- GHOST_IWindow *window;
- GHOST_TKey key;
- GHOST_TEventKeyData key_data;
+ GHOST_SystemWayland *system = nullptr;
+ GHOST_IWindow *window = nullptr;
+ GHOST_TEventKeyData key_data = {GHOST_kKeyUnknown};
};
struct input_t {
- GHOST_SystemWayland *system;
+ GHOST_SystemWayland *system = nullptr;
std::string name;
- struct wl_seat *seat;
- struct wl_pointer *pointer = nullptr;
- struct wl_keyboard *keyboard = nullptr;
+ struct wl_seat *wl_seat = nullptr;
+ struct wl_pointer *wl_pointer = nullptr;
+ struct wl_keyboard *wl_keyboard = nullptr;
struct zwp_tablet_seat_v2 *tablet_seat = nullptr;
/** All currently active tablet tools (needed for changing the cursor). */
std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools;
- uint32_t pointer_serial;
- uint32_t tablet_serial;
+ uint32_t pointer_serial = 0;
+ uint32_t tablet_serial = 0;
/** Use to check if the last cursor input was tablet or pointer. */
- uint32_t cursor_serial;
+ uint32_t cursor_serial = 0;
/**
* High precision mouse coordinates (pointer or tablet).
@@ -154,21 +155,21 @@ struct input_t {
* };
* \endocde
*/
- wl_fixed_t xy[2];
- GHOST_Buttons buttons;
+ wl_fixed_t xy[2] = {0, 0};
+ GHOST_Buttons buttons = GHOST_Buttons();
struct cursor_t cursor;
- struct zwp_relative_pointer_v1 *relative_pointer;
- struct zwp_locked_pointer_v1 *locked_pointer;
- struct zwp_confined_pointer_v1 *confined_pointer;
+ struct zwp_relative_pointer_v1 *relative_pointer = nullptr;
+ struct zwp_locked_pointer_v1 *locked_pointer = nullptr;
+ struct zwp_confined_pointer_v1 *confined_pointer = nullptr;
- struct xkb_context *xkb_context;
- struct xkb_state *xkb_state;
+ struct xkb_context *xkb_context = nullptr;
+ struct xkb_state *xkb_state = nullptr;
struct {
/** Key repetition in character per second. */
- int32_t rate;
+ int32_t rate = 0;
/** Time (milliseconds) after which to start repeating keys. */
- int32_t delay;
+ int32_t delay = 0;
/** Timer for key repeats. */
GHOST_ITimerTask *timer = nullptr;
} key_repeat;
@@ -180,33 +181,34 @@ struct input_t {
struct wl_data_device *data_device = nullptr;
/** Drag & Drop. */
- struct data_offer_t *data_offer_dnd;
+ struct data_offer_t *data_offer_dnd = nullptr;
std::mutex data_offer_dnd_mutex;
/** Copy & Paste. */
- struct data_offer_t *data_offer_copy_paste;
+ struct data_offer_t *data_offer_copy_paste = nullptr;
std::mutex data_offer_copy_paste_mutex;
- struct data_source_t *data_source;
+ struct data_source_t *data_source = nullptr;
std::mutex data_source_mutex;
/** Last device that was active. */
- uint32_t data_source_serial;
+ uint32_t data_source_serial = 0;
};
struct display_t {
- GHOST_SystemWayland *system;
+ GHOST_SystemWayland *system = nullptr;
- struct wl_display *display;
+ struct wl_display *display = nullptr;
struct wl_compositor *compositor = nullptr;
struct xdg_wm_base *xdg_shell = nullptr;
struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr;
+ struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct wl_shm *shm = nullptr;
std::vector<output_t *> outputs;
std::vector<input_t *> inputs;
struct {
std::string theme;
- int size;
+ int size = 0;
} cursor;
struct wl_data_device_manager *data_device_manager = nullptr;
struct zwp_tablet_manager_v2 *tablet_manager = nullptr;
@@ -256,7 +258,7 @@ static void display_destroy(display_t *d)
}
for (output_t *output : d->outputs) {
- wl_output_destroy(output->output);
+ wl_output_destroy(output->wl_output);
delete output;
}
@@ -275,28 +277,28 @@ static void display_destroy(display_t *d)
if (input->data_device) {
wl_data_device_release(input->data_device);
}
- if (input->pointer) {
+ if (input->wl_pointer) {
if (input->cursor.file_buffer) {
munmap(input->cursor.file_buffer->data, input->cursor.file_buffer->size);
delete input->cursor.file_buffer;
}
- if (input->cursor.surface) {
- wl_surface_destroy(input->cursor.surface);
+ if (input->cursor.wl_surface) {
+ wl_surface_destroy(input->cursor.wl_surface);
}
- if (input->cursor.theme) {
- wl_cursor_theme_destroy(input->cursor.theme);
+ if (input->cursor.wl_theme) {
+ wl_cursor_theme_destroy(input->cursor.wl_theme);
}
- if (input->pointer) {
- wl_pointer_destroy(input->pointer);
+ if (input->wl_pointer) {
+ wl_pointer_destroy(input->wl_pointer);
}
}
- if (input->keyboard) {
+ if (input->wl_keyboard) {
if (input->key_repeat.timer) {
delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData());
input->system->removeTimer(input->key_repeat.timer);
input->key_repeat.timer = nullptr;
}
- wl_keyboard_destroy(input->keyboard);
+ wl_keyboard_destroy(input->wl_keyboard);
}
if (input->xkb_state) {
xkb_state_unref(input->xkb_state);
@@ -304,7 +306,7 @@ static void display_destroy(display_t *d)
if (input->xkb_context) {
xkb_context_unref(input->xkb_context);
}
- wl_seat_destroy(input->seat);
+ wl_seat_destroy(input->wl_seat);
delete input;
}
@@ -550,7 +552,7 @@ static const std::vector<std::string> mime_send = {
* an event is received from the compositor.
* \{ */
-static void relative_pointer_relative_motion(
+static void relative_pointer_handle_relative_motion(
void *data,
struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/,
uint32_t /*utime_hi*/,
@@ -561,8 +563,8 @@ static void relative_pointer_relative_motion(
wl_fixed_t /*dy_unaccel*/)
{
input_t *input = static_cast<input_t *>(data);
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_pointer));
- if (win == nullptr) {
+ GHOST_WindowWayland *win = window_from_surface(input->focus_pointer);
+ if (!win) {
return;
}
const wl_fixed_t scale = win->scale();
@@ -578,7 +580,7 @@ static void relative_pointer_relative_motion(
}
static const zwp_relative_pointer_v1_listener relative_pointer_listener = {
- relative_pointer_relative_motion,
+ relative_pointer_handle_relative_motion,
};
/** \} */
@@ -643,17 +645,17 @@ static std::string read_pipe(data_offer_t *data_offer,
* Sent when a target accepts pointer_focus or motion events. If
* a target does not accept any of the offered types, type is nullptr.
*/
-static void data_source_target(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/,
- const char * /*mime_type*/)
+static void data_source_handle_target(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/)
{
/* pass */
}
-static void data_source_send(void *data,
- struct wl_data_source * /*wl_data_source*/,
- const char * /*mime_type*/,
- int32_t fd)
+static void data_source_handle_send(void *data,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/,
+ int32_t fd)
{
input_t *input = static_cast<input_t *>(data);
std::lock_guard lock{input->data_source_mutex};
@@ -665,7 +667,7 @@ static void data_source_send(void *data,
close(fd);
}
-static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
+static void data_source_handle_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
{
wl_data_source_destroy(wl_data_source);
}
@@ -677,8 +679,8 @@ static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_dat
* indicate acceptance, #wl_data_source.cancelled may still be
* emitted afterwards if the drop destination does not accept any mime type.
*/
-static void data_source_dnd_drop_performed(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/)
+static void data_source_handle_dnd_drop_performed(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/)
{
/* pass */
}
@@ -690,7 +692,8 @@ static void data_source_dnd_drop_performed(void * /*data*/,
* source, so the client is now free to destroy this data source
* and free all associated data.
*/
-static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*wl_data_source*/)
+static void data_source_handle_dnd_finished(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/)
{
/* pass */
}
@@ -702,20 +705,20 @@ static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*
* after matching the source/destination side actions. Only one
* action (or none) will be offered here.
*/
-static void data_source_action(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/,
- uint32_t /*dnd_action*/)
+static void data_source_handle_action(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ uint32_t /*dnd_action*/)
{
/* pass */
}
static const struct wl_data_source_listener data_source_listener = {
- data_source_target,
- data_source_send,
- data_source_cancelled,
- data_source_dnd_drop_performed,
- data_source_dnd_finished,
- data_source_action,
+ data_source_handle_target,
+ data_source_handle_send,
+ data_source_handle_cancelled,
+ data_source_handle_dnd_drop_performed,
+ data_source_handle_dnd_finished,
+ data_source_handle_action,
};
/** \} */
@@ -724,31 +727,31 @@ static const struct wl_data_source_listener data_source_listener = {
/** \name Listener (Data Offer), #wl_data_offer_listener
* \{ */
-static void data_offer_offer(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- const char *mime_type)
+static void data_offer_handle_offer(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ const char *mime_type)
{
static_cast<data_offer_t *>(data)->types.insert(mime_type);
}
-static void data_offer_source_actions(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- uint32_t source_actions)
+static void data_offer_handle_source_actions(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t source_actions)
{
static_cast<data_offer_t *>(data)->source_actions = source_actions;
}
-static void data_offer_action(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- uint32_t dnd_action)
+static void data_offer_handle_action(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t dnd_action)
{
static_cast<data_offer_t *>(data)->dnd_action = dnd_action;
}
static const struct wl_data_offer_listener data_offer_listener = {
- data_offer_offer,
- data_offer_source_actions,
- data_offer_action,
+ data_offer_handle_offer,
+ data_offer_handle_source_actions,
+ data_offer_handle_action,
};
/** \} */
@@ -757,22 +760,22 @@ static const struct wl_data_offer_listener data_offer_listener = {
/** \name Listener (Data Device), #wl_data_device_listener
* \{ */
-static void data_device_data_offer(void * /*data*/,
- struct wl_data_device * /*wl_data_device*/,
- struct wl_data_offer *id)
+static void data_device_handle_data_offer(void * /*data*/,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
{
data_offer_t *data_offer = new data_offer_t;
data_offer->id = id;
wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
}
-static void data_device_enter(void *data,
- struct wl_data_device * /*wl_data_device*/,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t x,
- wl_fixed_t y,
- struct wl_data_offer *id)
+static void data_device_handle_enter(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t x,
+ wl_fixed_t y,
+ struct wl_data_offer *id)
{
input_t *input = static_cast<input_t *>(data);
std::lock_guard lock{input->data_offer_dnd_mutex};
@@ -797,7 +800,7 @@ static void data_device_enter(void *data,
dnd_events(input, GHOST_kEventDraggingEntered);
}
-static void data_device_leave(void *data, struct wl_data_device * /*wl_data_device*/)
+static void data_device_handle_leave(void *data, struct wl_data_device * /*wl_data_device*/)
{
input_t *input = static_cast<input_t *>(data);
std::lock_guard lock{input->data_offer_dnd_mutex};
@@ -812,11 +815,11 @@ static void data_device_leave(void *data, struct wl_data_device * /*wl_data_devi
}
}
-static void data_device_motion(void *data,
- struct wl_data_device * /*wl_data_device*/,
- uint32_t /*time*/,
- wl_fixed_t x,
- wl_fixed_t y)
+static void data_device_handle_motion(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t /*time*/,
+ wl_fixed_t x,
+ wl_fixed_t y)
{
input_t *input = static_cast<input_t *>(data);
std::lock_guard lock{input->data_offer_dnd_mutex};
@@ -827,7 +830,7 @@ static void data_device_motion(void *data,
dnd_events(input, GHOST_kEventDraggingUpdated);
}
-static void data_device_drop(void *data, struct wl_data_device * /*wl_data_device*/)
+static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_data_device*/)
{
input_t *input = static_cast<input_t *>(data);
std::lock_guard lock{input->data_offer_dnd_mutex};
@@ -839,11 +842,11 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
data_offer->types.begin(),
data_offer->types.end());
- auto read_uris = [](input_t *const input,
- data_offer_t *data_offer,
- wl_surface *surface,
- const std::string mime_receive) {
- const wl_fixed_t *xy = data_offer->dnd.xy;
+ auto read_uris_fn = [](input_t *const input,
+ data_offer_t *data_offer,
+ wl_surface *surface,
+ const std::string mime_receive) {
+ const wl_fixed_t xy[2] = {data_offer->dnd.xy[0], data_offer->dnd.xy[1]};
const std::string data = read_pipe(data_offer, mime_receive, nullptr);
@@ -859,7 +862,7 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
static constexpr const char *file_proto = "file://";
static constexpr const char *crlf = "\r\n";
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface));
+ GHOST_WindowWayland *win = window_from_surface(surface);
GHOST_ASSERT(win != nullptr, "Unable to find window for drop event from surface");
std::vector<std::string> uris;
@@ -904,13 +907,13 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
/* Pass in `input->focus_dnd` instead of accessing it from `input` since the leave callback
* (#data_device_leave) will clear the value once this function starts. */
- std::thread read_thread(read_uris, input, data_offer, input->focus_dnd, mime_receive);
+ std::thread read_thread(read_uris_fn, input, data_offer, input->focus_dnd, mime_receive);
read_thread.detach();
}
-static void data_device_selection(void *data,
- struct wl_data_device * /*wl_data_device*/,
- struct wl_data_offer *id)
+static void data_device_handle_selection(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
{
input_t *input = static_cast<input_t *>(data);
@@ -933,7 +936,7 @@ static void data_device_selection(void *data,
data_offer = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
input->data_offer_copy_paste = data_offer;
- auto read_selection = [](input_t *input) {
+ auto read_selection_fn = [](input_t *input) {
GHOST_SystemWayland *const system = input->system;
input->data_offer_copy_paste_mutex.lock();
@@ -954,50 +957,55 @@ static void data_device_selection(void *data,
}
};
- std::thread read_thread(read_selection, input);
+ std::thread read_thread(read_selection_fn, input);
read_thread.detach();
}
static const struct wl_data_device_listener data_device_listener = {
- data_device_data_offer,
- data_device_enter,
- data_device_leave,
- data_device_motion,
- data_device_drop,
- data_device_selection,
+ data_device_handle_data_offer,
+ data_device_handle_enter,
+ data_device_handle_leave,
+ data_device_handle_motion,
+ data_device_handle_drop,
+ data_device_handle_selection,
};
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Listener (Surface), #wl_surface_listener
+/** \name Listener (Buffer), #wl_buffer_listener
* \{ */
-static void cursor_buffer_release(void *data, struct wl_buffer *wl_buffer)
+static void cursor_buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
{
cursor_t *cursor = static_cast<cursor_t *>(data);
wl_buffer_destroy(wl_buffer);
- if (wl_buffer == cursor->buffer) {
+ if (wl_buffer == cursor->wl_buffer) {
/* the mapped buffer was from a custom cursor */
- cursor->buffer = nullptr;
+ cursor->wl_buffer = nullptr;
}
}
const struct wl_buffer_listener cursor_buffer_listener = {
- cursor_buffer_release,
+ cursor_buffer_handle_release,
};
-static GHOST_IWindow *get_window(struct wl_surface *surface)
-{
- if (!surface) {
- return nullptr;
- }
+/** \} */
- for (GHOST_IWindow *win : window_manager->getWindows()) {
- if (surface == static_cast<const GHOST_WindowWayland *>(win)->surface()) {
- return win;
+/* -------------------------------------------------------------------- */
+/** \name Listener (Surface), #wl_surface_listener
+ * \{ */
+
+static GHOST_WindowWayland *window_from_surface(struct wl_surface *surface)
+{
+ if (surface) {
+ for (GHOST_IWindow *iwin : window_manager->getWindows()) {
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin);
+ if (surface == win->surface()) {
+ return win;
+ }
}
}
return nullptr;
@@ -1014,34 +1022,34 @@ static bool update_cursor_scale(cursor_t &cursor, wl_shm *shm)
if (scale > 0 && cursor.scale != scale) {
cursor.scale = scale;
- wl_surface_set_buffer_scale(cursor.surface, scale);
- wl_cursor_theme_destroy(cursor.theme);
- cursor.theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
+ wl_surface_set_buffer_scale(cursor.wl_surface, scale);
+ wl_cursor_theme_destroy(cursor.wl_theme);
+ cursor.wl_theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
return true;
}
return false;
}
-static void cursor_surface_enter(void *data,
- struct wl_surface * /*wl_surface*/,
- struct wl_output *output)
+static void cursor_surface_handle_enter(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
input_t *input = static_cast<input_t *>(data);
for (const output_t *reg_output : input->system->outputs()) {
- if (reg_output->output == output) {
+ if (reg_output->wl_output == output) {
input->cursor.outputs.insert(reg_output);
}
}
update_cursor_scale(input->cursor, input->system->shm());
}
-static void cursor_surface_leave(void *data,
- struct wl_surface * /*wl_surface*/,
- struct wl_output *output)
+static void cursor_surface_handle_leave(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
input_t *input = static_cast<input_t *>(data);
for (const output_t *reg_output : input->system->outputs()) {
- if (reg_output->output == output) {
+ if (reg_output->wl_output == output) {
input->cursor.outputs.erase(reg_output);
}
}
@@ -1049,8 +1057,8 @@ static void cursor_surface_leave(void *data,
}
struct wl_surface_listener cursor_surface_listener = {
- cursor_surface_enter,
- cursor_surface_leave,
+ cursor_surface_handle_enter,
+ cursor_surface_handle_leave,
};
/** \} */
@@ -1059,15 +1067,14 @@ struct wl_surface_listener cursor_surface_listener = {
/** \name Listener (Pointer), #wl_pointer_listener
* \{ */
-static void pointer_enter(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
+static void pointer_handle_enter(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
{
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface));
-
+ GHOST_WindowWayland *win = window_from_surface(surface);
if (!win) {
return;
}
@@ -1092,13 +1099,12 @@ static void pointer_enter(void *data,
GHOST_TABLET_DATA_NONE));
}
-static void pointer_leave(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*serial*/,
- struct wl_surface *surface)
+static void pointer_handle_leave(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface)
{
- GHOST_IWindow *win = get_window(surface);
-
+ GHOST_IWindow *win = window_from_surface(surface);
if (!win) {
return;
}
@@ -1107,16 +1113,14 @@ static void pointer_leave(void *data,
static_cast<GHOST_WindowWayland *>(win)->deactivate();
}
-static void pointer_motion(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*time*/,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
+static void pointer_handle_motion(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*time*/,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
{
input_t *input = static_cast<input_t *>(data);
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_pointer));
-
+ GHOST_WindowWayland *win = window_from_surface(input->focus_pointer);
if (!win) {
return;
}
@@ -1133,17 +1137,15 @@ static void pointer_motion(void *data,
GHOST_TABLET_DATA_NONE));
}
-static void pointer_button(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t serial,
- uint32_t /*time*/,
- uint32_t button,
- uint32_t state)
+static void pointer_handle_button(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ uint32_t /*time*/,
+ uint32_t button,
+ uint32_t state)
{
input_t *input = static_cast<input_t *>(data);
-
- GHOST_IWindow *win = get_window(input->focus_pointer);
-
+ GHOST_IWindow *win = window_from_surface(input->focus_pointer);
if (!win) {
return;
}
@@ -1189,16 +1191,14 @@ static void pointer_button(void *data,
input->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE));
}
-static void pointer_axis(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*time*/,
- uint32_t axis,
- wl_fixed_t value)
+static void pointer_handle_axis(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*time*/,
+ uint32_t axis,
+ wl_fixed_t value)
{
input_t *input = static_cast<input_t *>(data);
-
- GHOST_IWindow *win = get_window(input->focus_pointer);
-
+ GHOST_IWindow *win = window_from_surface(input->focus_pointer);
if (!win) {
return;
}
@@ -1212,11 +1212,11 @@ static void pointer_axis(void *data,
}
static const struct wl_pointer_listener pointer_listener = {
- pointer_enter,
- pointer_leave,
- pointer_motion,
- pointer_button,
- pointer_axis,
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
};
/** \} */
@@ -1225,39 +1225,41 @@ static const struct wl_pointer_listener pointer_listener = {
/** \name Listener (Tablet Tool), #zwp_tablet_tool_v2_listener
* \{ */
-static void tablet_tool_type(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t tool_type)
+static void tablet_tool_handle_type(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t tool_type)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
tool_input->data.Active = tablet_tool_map_type((enum zwp_tablet_tool_v2_type)tool_type);
}
-static void tablet_tool_hardware_serial(void * /*data*/,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t /*hardware_serial_hi*/,
- uint32_t /*hardware_serial_lo*/)
+static void tablet_tool_handle_hardware_serial(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*hardware_serial_hi*/,
+ uint32_t /*hardware_serial_lo*/)
{
}
-static void tablet_tool_hardware_id_wacom(void * /*data*/,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t /*hardware_id_hi*/,
- uint32_t /*hardware_id_lo*/)
+static void tablet_tool_handle_hardware_id_wacom(
+ void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*hardware_id_hi*/,
+ uint32_t /*hardware_id_lo*/)
{
}
-static void tablet_tool_capability(void * /*data*/,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t /*capability*/)
+static void tablet_tool_handle_capability(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*capability*/)
{
}
-static void tablet_tool_done(void * /*data*/, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+static void tablet_tool_handle_done(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
{
}
-static void tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2)
+static void tablet_tool_handle_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
@@ -1269,11 +1271,11 @@ static void tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *zwp_table
delete tool_input;
}
-static void tablet_tool_proximity_in(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t serial,
- struct zwp_tablet_v2 * /*tablet*/,
- struct wl_surface *surface)
+static void tablet_tool_handle_proximity_in(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t serial,
+ struct zwp_tablet_v2 * /*tablet*/,
+ struct wl_surface *surface)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
@@ -1285,13 +1287,6 @@ static void tablet_tool_proximity_in(void *data,
input->data_source_serial = serial;
/* Update #GHOST_TabletData. */
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
- if (!win) {
- return;
- }
-
- win->activate();
-
GHOST_TabletData &td = tool_input->data;
/* Reset, to avoid using stale tilt/pressure. */
td.Xtilt = 0.0f;
@@ -1299,28 +1294,35 @@ static void tablet_tool_proximity_in(void *data,
/* In case pressure isn't supported. */
td.Pressure = 1.0f;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
+ win->activate();
+
win->setCursorShape(win->getCursorShape());
}
-static void tablet_tool_proximity_out(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+static void tablet_tool_handle_proximity_out(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
-
input->focus_tablet = nullptr;
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
+ if (!win) {
+ return;
+ }
win->setCursorShape(win->getCursorShape());
}
-static void tablet_tool_down(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t serial)
+static void tablet_tool_handle_down(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t serial)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
if (!win) {
return;
}
@@ -1333,15 +1335,15 @@ static void tablet_tool_down(void *data,
input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
}
-static void tablet_tool_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+static void tablet_tool_handle_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
if (!win) {
return;
}
+
const GHOST_TEventType etype = GHOST_kEventButtonUp;
const GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
input->buttons.set(ebutton, false);
@@ -1349,15 +1351,14 @@ static void tablet_tool_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_tablet_
input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
}
-static void tablet_tool_motion(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- wl_fixed_t x,
- wl_fixed_t y)
+static void tablet_tool_handle_motion(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ wl_fixed_t x,
+ wl_fixed_t y)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
if (!win) {
return;
}
@@ -1374,34 +1375,33 @@ static void tablet_tool_motion(void *data,
tool_input->data));
}
-static void tablet_tool_pressure(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t pressure)
+static void tablet_tool_handle_pressure(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t pressure)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
if (!win) {
return;
}
+
GHOST_TabletData &td = tool_input->data;
td.Pressure = (float)pressure / 65535;
}
-static void tablet_tool_distance(void * /*data*/,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t /*distance*/)
+static void tablet_tool_handle_distance(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*distance*/)
{
}
-static void tablet_tool_tilt(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- wl_fixed_t tilt_x,
- wl_fixed_t tilt_y)
+static void tablet_tool_handle_tilt(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ wl_fixed_t tilt_x,
+ wl_fixed_t tilt_y)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
if (!win) {
return;
}
@@ -1414,23 +1414,23 @@ static void tablet_tool_tilt(void *data,
td.Ytilt = td.Ytilt < -1.0f ? -1.0f : (td.Ytilt > 1.0f ? 1.0f : td.Ytilt);
}
-static void tablet_tool_rotation(void * /*data*/,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- wl_fixed_t /*degrees*/)
+static void tablet_tool_handle_rotation(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ wl_fixed_t /*degrees*/)
{
/* Pass. */
}
-static void tablet_tool_slider(void * /*data*/,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- int32_t /*position*/)
+static void tablet_tool_handle_slider(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ int32_t /*position*/)
{
/* Pass. */
}
-static void tablet_tool_wheel(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- wl_fixed_t /*degrees*/,
- int32_t clicks)
+static void tablet_tool_handle_wheel(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ wl_fixed_t /*degrees*/,
+ int32_t clicks)
{
if (clicks == 0) {
return;
@@ -1438,22 +1438,22 @@ static void tablet_tool_wheel(void *data,
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
if (!win) {
return;
}
+
input->system->pushEvent(new GHOST_EventWheel(input->system->getMilliSeconds(), win, clicks));
}
-static void tablet_tool_button(void *data,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t serial,
- uint32_t button,
- uint32_t state)
+static void tablet_tool_handle_button(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t serial,
+ uint32_t button,
+ uint32_t state)
{
tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
input_t *input = tool_input->input;
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+ GHOST_WindowWayland *win = window_from_surface(input->focus_tablet);
if (!win) {
return;
}
@@ -1486,32 +1486,32 @@ static void tablet_tool_button(void *data,
input->system->pushEvent(new GHOST_EventButton(
input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
}
-static void tablet_tool_frame(void * /*data*/,
- struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
- uint32_t /*time*/)
+static void tablet_tool_handle_frame(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ uint32_t /*time*/)
{
}
static const struct zwp_tablet_tool_v2_listener tablet_tool_listner = {
- tablet_tool_type,
- tablet_tool_hardware_serial,
- tablet_tool_hardware_id_wacom,
- tablet_tool_capability,
- tablet_tool_done,
- tablet_tool_removed,
- tablet_tool_proximity_in,
- tablet_tool_proximity_out,
- tablet_tool_down,
- tablet_tool_up,
- tablet_tool_motion,
- tablet_tool_pressure,
- tablet_tool_distance,
- tablet_tool_tilt,
- tablet_tool_rotation,
- tablet_tool_slider,
- tablet_tool_wheel,
- tablet_tool_button,
- tablet_tool_frame,
+ tablet_tool_handle_type,
+ tablet_tool_handle_hardware_serial,
+ tablet_tool_handle_hardware_id_wacom,
+ tablet_tool_handle_capability,
+ tablet_tool_handle_done,
+ tablet_tool_handle_removed,
+ tablet_tool_handle_proximity_in,
+ tablet_tool_handle_proximity_out,
+ tablet_tool_handle_down,
+ tablet_tool_handle_up,
+ tablet_tool_handle_motion,
+ tablet_tool_handle_pressure,
+ tablet_tool_handle_distance,
+ tablet_tool_handle_tilt,
+ tablet_tool_handle_rotation,
+ tablet_tool_handle_slider,
+ tablet_tool_handle_wheel,
+ tablet_tool_handle_button,
+ tablet_tool_handle_frame,
};
/** \} */
@@ -1520,16 +1520,16 @@ static const struct zwp_tablet_tool_v2_listener tablet_tool_listner = {
/** \name Listener (Table Seat), #zwp_tablet_seat_v2_listener
* \{ */
-static void tablet_seat_tablet_added(void * /*data*/,
- struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
- struct zwp_tablet_v2 * /*id*/)
+static void tablet_seat_handle_tablet_added(void * /*data*/,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_v2 * /*id*/)
{
/* Pass. */
}
-static void tablet_seat_tool_added(void *data,
- struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
- struct zwp_tablet_tool_v2 *id)
+static void tablet_seat_handle_tool_added(void *data,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_tool_v2 *id)
{
input_t *input = static_cast<input_t *>(data);
tablet_tool_input_t *tool_input = new tablet_tool_input_t();
@@ -1539,24 +1539,22 @@ static void tablet_seat_tool_added(void *data,
tool_input->cursor_surface = wl_compositor_create_surface(input->system->compositor());
wl_surface_add_listener(tool_input->cursor_surface, &cursor_surface_listener, (void *)input);
- tool_input->data = GHOST_TABLET_DATA_NONE;
-
zwp_tablet_tool_v2_add_listener(id, &tablet_tool_listner, tool_input);
input->tablet_tools.insert(id);
}
-static void tablet_seat_pad_added(void * /*data*/,
- struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
- struct zwp_tablet_pad_v2 * /*id*/)
+static void tablet_seat_handle_pad_added(void * /*data*/,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_pad_v2 * /*id*/)
{
/* Pass. */
}
const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
- tablet_seat_tablet_added,
- tablet_seat_tool_added,
- tablet_seat_pad_added,
+ tablet_seat_handle_tablet_added,
+ tablet_seat_handle_tool_added,
+ tablet_seat_handle_pad_added,
};
/** \} */
@@ -1565,7 +1563,7 @@ const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
/** \name Listener (Keyboard), #wl_keyboard_listener
* \{ */
-static void keyboard_keymap(
+static void keyboard_handle_keymap(
void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t format, int32_t fd, uint32_t size)
{
input_t *input = static_cast<input_t *>(data);
@@ -1601,11 +1599,11 @@ static void keyboard_keymap(
* Notification that this seat's keyboard focus is on a certain
* surface.
*/
-static void keyboard_enter(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- struct wl_surface *surface,
- struct wl_array * /*keys*/)
+static void keyboard_handle_enter(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface,
+ struct wl_array * /*keys*/)
{
if (surface != nullptr) {
static_cast<input_t *>(data)->focus_keyboard = surface;
@@ -1618,10 +1616,10 @@ static void keyboard_enter(void *data,
* Notification that this seat's keyboard focus is no longer on a
* certain surface.
*/
-static void keyboard_leave(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- struct wl_surface *surface)
+static void keyboard_handle_leave(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface)
{
if (surface != nullptr) {
static_cast<input_t *>(data)->focus_keyboard = nullptr;
@@ -1654,12 +1652,12 @@ static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(struct xkb_state
return sym;
}
-static void keyboard_key(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t serial,
- uint32_t /*time*/,
- uint32_t key,
- uint32_t state)
+static void keyboard_handle_key(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t serial,
+ uint32_t /*time*/,
+ uint32_t key,
+ uint32_t state)
{
input_t *input = static_cast<input_t *>(data);
@@ -1678,7 +1676,6 @@ static void keyboard_key(void *data,
if (sym == XKB_KEY_NoSymbol) {
return;
}
- const GHOST_TKey gkey = xkb_map_gkey(sym);
/* Delete previous timer. */
if (xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) &&
@@ -1688,7 +1685,9 @@ static void keyboard_key(void *data,
input->key_repeat.timer = nullptr;
}
- GHOST_TEventKeyData key_data;
+ GHOST_TEventKeyData key_data = {
+ .key = xkb_map_gkey(sym),
+ };
if (etype == GHOST_kEventKeyDown) {
xkb_state_key_get_utf8(
@@ -1703,7 +1702,7 @@ static void keyboard_key(void *data,
GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
wl_surface_get_user_data(input->focus_keyboard));
input->system->pushEvent(new GHOST_EventKey(
- input->system->getMilliSeconds(), etype, win, gkey, '\0', key_data.utf8_buf, false));
+ input->system->getMilliSeconds(), etype, win, key_data.key, '\0', key_data.utf8_buf, false));
/* Start timer for repeating key, if applicable. */
if (input->key_repeat.rate > 0 &&
@@ -1713,33 +1712,32 @@ static void keyboard_key(void *data,
key_repeat_payload_t *payload = new key_repeat_payload_t({
.system = input->system,
.window = win,
- .key = gkey,
.key_data = key_data,
});
- auto cb = [](GHOST_ITimerTask *task, uint64_t /*time*/) {
+ auto key_repeat_fn = [](GHOST_ITimerTask *task, uint64_t /*time*/) {
struct key_repeat_payload_t *payload = static_cast<key_repeat_payload_t *>(
task->getUserData());
payload->system->pushEvent(new GHOST_EventKey(payload->system->getMilliSeconds(),
GHOST_kEventKeyDown,
payload->window,
- payload->key,
+ payload->key_data.key,
'\0',
payload->key_data.utf8_buf,
true));
};
input->key_repeat.timer = input->system->installTimer(
- input->key_repeat.delay, 1000 / input->key_repeat.rate, cb, payload);
+ input->key_repeat.delay, 1000 / input->key_repeat.rate, key_repeat_fn, payload);
}
}
-static void keyboard_modifiers(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- uint32_t mods_depressed,
- uint32_t mods_latched,
- uint32_t mods_locked,
- uint32_t group)
+static void keyboard_handle_modifiers(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
{
xkb_state_update_mask(static_cast<input_t *>(data)->xkb_state,
mods_depressed,
@@ -1750,10 +1748,10 @@ static void keyboard_modifiers(void *data,
group);
}
-static void keyboard_repeat_info(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- int32_t rate,
- int32_t delay)
+static void keyboard_repeat_handle_info(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ int32_t rate,
+ int32_t delay)
{
input_t *input = static_cast<input_t *>(data);
@@ -1762,12 +1760,12 @@ static void keyboard_repeat_info(void *data,
}
static const struct wl_keyboard_listener keyboard_listener = {
- keyboard_keymap,
- keyboard_enter,
- keyboard_leave,
- keyboard_key,
- keyboard_modifiers,
- keyboard_repeat_info,
+ keyboard_handle_keymap,
+ keyboard_handle_enter,
+ keyboard_handle_leave,
+ keyboard_handle_key,
+ keyboard_handle_modifiers,
+ keyboard_repeat_handle_info,
};
/** \} */
@@ -1776,40 +1774,113 @@ static const struct wl_keyboard_listener keyboard_listener = {
/** \name Listener (Seat), #wl_seat_listener
* \{ */
-static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
+static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
{
input_t *input = static_cast<input_t *>(data);
- input->pointer = nullptr;
- input->keyboard = nullptr;
+ input->wl_pointer = nullptr;
+ input->wl_keyboard = nullptr;
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
- input->pointer = wl_seat_get_pointer(wl_seat);
- input->cursor.surface = wl_compositor_create_surface(input->system->compositor());
+ input->wl_pointer = wl_seat_get_pointer(wl_seat);
+ input->cursor.wl_surface = wl_compositor_create_surface(input->system->compositor());
input->cursor.visible = true;
- input->cursor.buffer = nullptr;
+ input->cursor.wl_buffer = nullptr;
input->cursor.file_buffer = new buffer_t;
if (!get_cursor_settings(input->cursor.theme_name, input->cursor.size)) {
input->cursor.theme_name = std::string();
input->cursor.size = default_cursor_size;
}
- wl_pointer_add_listener(input->pointer, &pointer_listener, data);
- wl_surface_add_listener(input->cursor.surface, &cursor_surface_listener, data);
+ wl_pointer_add_listener(input->wl_pointer, &pointer_listener, data);
+ wl_surface_add_listener(input->cursor.wl_surface, &cursor_surface_listener, data);
}
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
- input->keyboard = wl_seat_get_keyboard(wl_seat);
- wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
+ input->wl_keyboard = wl_seat_get_keyboard(wl_seat);
+ wl_keyboard_add_listener(input->wl_keyboard, &keyboard_listener, data);
}
}
-static void seat_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
+static void seat_handle_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
{
static_cast<input_t *>(data)->name = std::string(name);
}
static const struct wl_seat_listener seat_listener = {
- seat_capabilities,
- seat_name,
+ seat_handle_capabilities,
+ seat_handle_name,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Output), #zxdg_output_v1_listener
+ * \{ */
+
+static void xdg_output_handle_logical_position(void *data,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ int32_t x,
+ int32_t y)
+{
+ output_t *output = static_cast<output_t *>(data);
+ output->position_logical[0] = x;
+ output->position_logical[1] = y;
+ output->has_position_logical = true;
+}
+
+static void xdg_output_handle_logical_size(void *data,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ int32_t width,
+ int32_t height)
+{
+ output_t *output = static_cast<output_t *>(data);
+
+ if (output->size_logical[0] != 0 && output->size_logical[1] != 0) {
+ /* Original comment from SDL. */
+ /* FIXME: GNOME has a bug where the logical size does not account for
+ * scale, resulting in bogus viewport sizes.
+ *
+ * Until this is fixed, validate that _some_ kind of scaling is being
+ * done (we can't match exactly because fractional scaling can't be
+ * detected otherwise), then override if necessary.
+ * -flibit
+ */
+ if ((output->size_logical[0] == width) && (output->scale_fractional == wl_fixed_from_int(1))) {
+ GHOST_PRINT("xdg_output scale did not match, overriding with wl_output scale");
+ return;
+ }
+ }
+
+ output->size_logical[0] = width;
+ output->size_logical[1] = height;
+ output->has_size_logical = true;
+}
+
+static void xdg_output_handle_done(void * /*data*/, struct zxdg_output_v1 * /*xdg_output*/)
+{
+ /* NOTE: `xdg-output.done` events are deprecated and only apply below version 3 of the protocol.
+ * `wl-output.done` event will be emitted in version 3 or higher. */
+}
+
+static void xdg_output_handle_name(void * /*data*/,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ const char * /*name*/)
+{
+ /* Pass. */
+}
+
+static void xdg_output_handle_description(void * /*data*/,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ const char * /*description*/)
+{
+ /* Pass. */
+}
+
+static const struct zxdg_output_v1_listener xdg_output_listener = {
+ xdg_output_handle_logical_position,
+ xdg_output_handle_logical_size,
+ xdg_output_handle_done,
+ xdg_output_handle_name,
+ xdg_output_handle_description,
};
/** \} */
@@ -1818,35 +1889,45 @@ static const struct wl_seat_listener seat_listener = {
/** \name Listener (Output), #wl_output_listener
* \{ */
-static void output_geometry(void *data,
- struct wl_output * /*wl_output*/,
- int32_t /*x*/,
- int32_t /*y*/,
- int32_t physical_width,
- int32_t physical_height,
- int32_t /*subpixel*/,
- const char *make,
- const char *model,
- int32_t transform)
+static void output_handle_geometry(void *data,
+ struct wl_output * /*wl_output*/,
+ int32_t /*x*/,
+ int32_t /*y*/,
+ int32_t physical_width,
+ int32_t physical_height,
+ int32_t /*subpixel*/,
+ const char *make,
+ const char *model,
+ int32_t transform)
{
output_t *output = static_cast<output_t *>(data);
output->transform = transform;
output->make = std::string(make);
output->model = std::string(model);
- output->width_mm = physical_width;
- output->height_mm = physical_height;
+ output->size_mm[0] = physical_width;
+ output->size_mm[1] = physical_height;
}
-static void output_mode(void *data,
- struct wl_output * /*wl_output*/,
- uint32_t /*flags*/,
- int32_t width,
- int32_t height,
- int32_t /*refresh*/)
+static void output_handle_mode(void *data,
+ struct wl_output * /*wl_output*/,
+ uint32_t flags,
+ int32_t width,
+ int32_t height,
+ int32_t /*refresh*/)
{
output_t *output = static_cast<output_t *>(data);
- output->width_pxl = width;
- output->height_pxl = height;
+
+ if (flags & WL_OUTPUT_MODE_CURRENT) {
+ output->size_native[0] = width;
+ output->size_native[1] = height;
+
+ /* Don't rotate this yet, `wl-output` coordinates are transformed in
+ * handle_done and `xdg-output` coordinates are pre-transformed. */
+ if (!output->has_size_logical) {
+ output->size_logical[0] = width;
+ output->size_logical[1] = height;
+ }
+ }
}
/**
@@ -1857,20 +1938,43 @@ static void output_mode(void *data,
* changes done after that. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
*/
-static void output_done(void * /*data*/, struct wl_output * /*wl_output*/)
+static void output_handle_done(void *data, struct wl_output * /*wl_output*/)
{
+ output_t *output = static_cast<output_t *>(data);
+ int32_t size_native[2];
+ if (output->transform & WL_OUTPUT_TRANSFORM_90) {
+ size_native[0] = output->size_native[1];
+ size_native[1] = output->size_native[1];
+ }
+ else {
+ size_native[0] = output->size_native[0];
+ size_native[1] = output->size_native[1];
+ }
+
+ /* If `xdg-output` is present, calculate the true scale of the desktop */
+ if (output->has_size_logical) {
+
+ /* NOTE: it's not necessary to divide these values by their greatest-common-denominator
+ * as even a 64k screen resolution doesn't approach overflowing an `int32_t`. */
+
+ GHOST_ASSERT(size_native[0] && output->size_logical[0],
+ "Screen size values were not set when they were expected to be.");
+
+ output->scale_fractional = wl_fixed_from_int(size_native[0]) / output->size_logical[0];
+ output->has_scale_fractional = true;
+ }
}
-static void output_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
+static void output_handle_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
{
static_cast<output_t *>(data)->scale = factor;
}
static const struct wl_output_listener output_listener = {
- output_geometry,
- output_mode,
- output_done,
- output_scale,
+ output_handle_geometry,
+ output_handle_mode,
+ output_handle_done,
+ output_handle_scale,
};
/** \} */
@@ -1879,13 +1983,13 @@ static const struct wl_output_listener output_listener = {
/** \name Listener (XDG WM Base), #xdg_wm_base_listener
* \{ */
-static void shell_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
+static void shell_handle_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener shell_listener = {
- shell_ping,
+ shell_handle_ping,
};
/** \} */
@@ -1894,11 +1998,11 @@ static const struct xdg_wm_base_listener shell_listener = {
/** \name Listener (Registry), #wl_registry_listener
* \{ */
-static void global_add(void *data,
- struct wl_registry *wl_registry,
- uint32_t name,
- const char *interface,
- uint32_t /*version*/)
+static void global_handle_add(void *data,
+ struct wl_registry *wl_registry,
+ uint32_t name,
+ const char *interface,
+ uint32_t /*version*/)
{
struct display_t *display = static_cast<struct display_t *>(data);
if (!strcmp(interface, wl_compositor_interface.name)) {
@@ -1914,31 +2018,37 @@ static void global_add(void *data,
display->xdg_decoration_manager = static_cast<zxdg_decoration_manager_v1 *>(
wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1));
}
+ else if (!strcmp(interface, zxdg_output_manager_v1_interface.name)) {
+ display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>(
+ wl_registry_bind(wl_registry, name, &zxdg_output_manager_v1_interface, 3));
+ for (output_t *output : display->outputs) {
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
+ output->wl_output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ }
+ }
else if (!strcmp(interface, wl_output_interface.name)) {
output_t *output = new output_t;
- output->scale = 1;
- output->output = static_cast<wl_output *>(
+ output->wl_output = static_cast<wl_output *>(
wl_registry_bind(wl_registry, name, &wl_output_interface, 2));
display->outputs.push_back(output);
- wl_output_add_listener(output->output, &output_listener, output);
+ wl_output_add_listener(output->wl_output, &output_listener, output);
+
+ if (display->xdg_output_manager) {
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
+ output->wl_output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ }
}
else if (!strcmp(interface, wl_seat_interface.name)) {
input_t *input = new input_t;
input->system = display->system;
input->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
- input->xkb_state = nullptr;
- input->data_offer_dnd = nullptr;
- input->data_offer_copy_paste = nullptr;
input->data_source = new data_source_t;
- input->data_source->data_source = nullptr;
- input->data_source->buffer_out = nullptr;
- input->relative_pointer = nullptr;
- input->locked_pointer = nullptr;
- input->confined_pointer = nullptr;
- input->seat = static_cast<wl_seat *>(
+ input->wl_seat = static_cast<wl_seat *>(
wl_registry_bind(wl_registry, name, &wl_seat_interface, 4));
display->inputs.push_back(input);
- wl_seat_add_listener(input->seat, &seat_listener, input);
+ wl_seat_add_listener(input->wl_seat, &seat_listener, input);
}
else if (!strcmp(interface, wl_shm_interface.name)) {
display->shm = static_cast<wl_shm *>(
@@ -1971,13 +2081,15 @@ static void global_add(void *data,
* name is no longer available. If the client bound to the global
* using the bind request, the client should now destroy that object.
*/
-static void global_remove(void * /*data*/, struct wl_registry * /*wl_registry*/, uint32_t /*name*/)
+static void global_handle_remove(void * /*data*/,
+ struct wl_registry * /*wl_registry*/,
+ uint32_t /*name*/)
{
}
static const struct wl_registry_listener registry_listener = {
- global_add,
- global_remove,
+ global_handle_add,
+ global_handle_remove,
};
/** \} */
@@ -2018,14 +2130,15 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
if (d->data_device_manager) {
for (input_t *input : d->inputs) {
input->data_device = wl_data_device_manager_get_data_device(d->data_device_manager,
- input->seat);
+ input->wl_seat);
wl_data_device_add_listener(input->data_device, &data_device_listener, input);
}
}
if (d->tablet_manager) {
for (input_t *input : d->inputs) {
- input->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(d->tablet_manager, input->seat);
+ input->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(d->tablet_manager,
+ input->wl_seat);
zwp_tablet_seat_v2_add_listener(input->tablet_seat, &tablet_seat_listener, input);
}
}
@@ -2163,6 +2276,10 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) co
}
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface));
+ if (!win) {
+ return GHOST_kFailure;
+ }
+
const wl_fixed_t scale = win->scale();
x = wl_fixed_to_int(scale * input->xy[0]);
y = wl_fixed_to_int(scale * input->xy[1]);
@@ -2178,8 +2295,8 @@ void GHOST_SystemWayland::getMainDisplayDimensions(uint32_t &width, uint32_t &he
{
if (getNumDisplays() > 0) {
/* We assume first output as main. */
- width = uint32_t(d->outputs[0]->width_pxl) / d->outputs[0]->scale;
- height = uint32_t(d->outputs[0]->height_pxl) / d->outputs[0]->scale;
+ width = uint32_t(d->outputs[0]->size_native[0]) / d->outputs[0]->scale;
+ height = uint32_t(d->outputs[0]->size_native[1]) / d->outputs[0]->scale;
}
}
@@ -2300,12 +2417,12 @@ wl_compositor *GHOST_SystemWayland::compositor()
return d->compositor;
}
-xdg_wm_base *GHOST_SystemWayland::shell()
+xdg_wm_base *GHOST_SystemWayland::xdg_shell()
{
return d->xdg_shell;
}
-zxdg_decoration_manager_v1 *GHOST_SystemWayland::decoration_manager()
+zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager()
{
return d->xdg_decoration_manager;
}
@@ -2331,22 +2448,22 @@ static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
c->visible = (buffer != nullptr);
- const int32_t image_size_x = int32_t(c->image.width);
- const int32_t image_size_y = int32_t(c->image.height);
+ const int32_t image_size_x = int32_t(c->wl_image.width);
+ const int32_t image_size_y = int32_t(c->wl_image.height);
- const int32_t hotspot_x = int32_t(c->image.hotspot_x) / c->scale;
- const int32_t hotspot_y = int32_t(c->image.hotspot_y) / c->scale;
+ const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / c->scale;
+ const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / c->scale;
- wl_surface_attach(c->surface, buffer, 0, 0);
- wl_surface_damage(c->surface, 0, 0, image_size_x, image_size_y);
+ wl_surface_attach(c->wl_surface, buffer, 0, 0);
+ wl_surface_damage(c->wl_surface, 0, 0, image_size_x, image_size_y);
- wl_pointer_set_cursor(input->pointer,
+ wl_pointer_set_cursor(input->wl_pointer,
input->pointer_serial,
- c->visible ? c->surface : nullptr,
+ c->visible ? c->wl_surface : nullptr,
hotspot_x,
hotspot_y);
- wl_surface_commit(c->surface);
+ wl_surface_commit(c->wl_surface);
/* Set the cursor for all tablet tools as well. */
for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) {
@@ -2379,12 +2496,13 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
input_t *input = d->inputs[0];
cursor_t *c = &input->cursor;
- if (!c->theme) {
+ if (!c->wl_theme) {
/* The cursor surface hasn't entered an output yet. Initialize theme with scale 1. */
- c->theme = wl_cursor_theme_load(c->theme_name.c_str(), c->size, d->inputs[0]->system->shm());
+ c->wl_theme = wl_cursor_theme_load(
+ c->theme_name.c_str(), c->size, d->inputs[0]->system->shm());
}
- wl_cursor *cursor = wl_cursor_theme_get_cursor(c->theme, cursor_name.c_str());
+ wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name.c_str());
if (!cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
@@ -2397,8 +2515,8 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
return GHOST_kFailure;
}
- c->buffer = buffer;
- c->image = *image;
+ c->wl_buffer = buffer;
+ c->wl_image = *image;
set_cursor_buffer(input, buffer);
@@ -2504,11 +2622,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
}
}
- cursor->buffer = buffer;
- cursor->image.width = uint32_t(sizex);
- cursor->image.height = uint32_t(sizey);
- cursor->image.hotspot_x = uint32_t(hotX);
- cursor->image.hotspot_y = uint32_t(hotY);
+ cursor->wl_buffer = buffer;
+ cursor->wl_image.width = uint32_t(sizex);
+ cursor->wl_image.height = uint32_t(sizey);
+ cursor->wl_image.hotspot_x = uint32_t(hotX);
+ cursor->wl_image.hotspot_y = uint32_t(hotY);
set_cursor_buffer(d->inputs[0], buffer);
@@ -2526,7 +2644,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
cursor_t *cursor = &input->cursor;
if (visible) {
if (!cursor->visible) {
- set_cursor_buffer(input, cursor->buffer);
+ set_cursor_buffer(input, cursor->wl_buffer);
}
}
else {
@@ -2545,7 +2663,6 @@ bool GHOST_SystemWayland::supportsCursorWarp()
GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
const GHOST_TGrabCursorMode mode_current,
-
wl_surface *surface)
{
/* ignore, if the required protocols are not supported */
@@ -2597,39 +2714,45 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
if (input->locked_pointer) {
/* Request location to restore to. */
if (mode_current == GHOST_kGrabWrap) {
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface));
- GHOST_Rect bounds;
- int32_t xy_new[2] = {input->xy[0], input->xy[1]};
-
- /* Fallback to window bounds. */
- if (win->getCursorGrabBounds(bounds) == GHOST_kFailure) {
- win->getClientBounds(bounds);
+ /* The chance this fails is _very_ low. */
+ GHOST_WindowWayland *win = window_from_surface(surface);
+ if (!win) {
+ GHOST_PRINT("could not find window from surface when un-grabbing!" << std::endl);
}
-
- const int scale = win->scale();
-
- 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.wrapPoint(xy_new[0], xy_new[1], 0, win->getCursorGrabAxis());
-
- /* Push an event so the new location is registered. */
- if ((xy_new[0] != input->xy[0]) || (xy_new[1] != input->xy[1])) {
- input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
- GHOST_kEventCursorMove,
- win,
- wl_fixed_to_int(scale * xy_new[0]),
- wl_fixed_to_int(scale * xy_new[1]),
- GHOST_TABLET_DATA_NONE));
+ else {
+ GHOST_Rect bounds;
+ int32_t xy_new[2] = {input->xy[0], input->xy[1]};
+
+ /* Fallback to window bounds. */
+ if (win->getCursorGrabBounds(bounds) == GHOST_kFailure) {
+ win->getClientBounds(bounds);
+ }
+
+ const int scale = win->scale();
+
+ 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.wrapPoint(xy_new[0], xy_new[1], 0, win->getCursorGrabAxis());
+
+ /* Push an event so the new location is registered. */
+ if ((xy_new[0] != input->xy[0]) || (xy_new[1] != input->xy[1])) {
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ win,
+ wl_fixed_to_int(scale * xy_new[0]),
+ wl_fixed_to_int(scale * xy_new[1]),
+ GHOST_TABLET_DATA_NONE));
+ }
+ input->xy[0] = xy_new[0];
+ input->xy[1] = xy_new[1];
+
+ zwp_locked_pointer_v1_set_cursor_position_hint(
+ input->locked_pointer, xy_new[0], xy_new[1]);
+ wl_surface_commit(surface);
}
- input->xy[0] = xy_new[0];
- input->xy[1] = xy_new[1];
-
- zwp_locked_pointer_v1_set_cursor_position_hint(
- input->locked_pointer, xy_new[0], xy_new[1]);
- wl_surface_commit(surface);
}
zwp_locked_pointer_v1_destroy(input->locked_pointer);
@@ -2652,13 +2775,13 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
* An alternative could be to draw the cursor in software (and hide the real cursor),
* or just accept a locked cursor on WAYLAND. */
input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
- d->relative_pointer_manager, input->pointer);
+ d->relative_pointer_manager, input->wl_pointer);
zwp_relative_pointer_v1_add_listener(
input->relative_pointer, &relative_pointer_listener, input);
input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
d->pointer_constraints,
surface,
- input->pointer,
+ input->wl_pointer,
nullptr,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
@@ -2668,7 +2791,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
input->confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
d->pointer_constraints,
surface,
- input->pointer,
+ input->wl_pointer,
nullptr,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 5b3e4f8ed75..3be108b1f88 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -22,11 +22,32 @@ class GHOST_WindowWayland;
struct display_t;
struct output_t {
- struct wl_output *output;
- int32_t width_pxl, height_pxl; /* Dimensions in pixel. */
- int32_t width_mm, height_mm; /* Dimensions in millimeter. */
- int transform;
- int scale;
+ struct wl_output *wl_output = nullptr;
+ struct zxdg_output_v1 *xdg_output = nullptr;
+ /** Dimensions in pixels. */
+ int32_t size_native[2] = {0, 0};
+ /** Dimensions in millimeter. */
+ int32_t size_mm[2] = {0, 0};
+
+ int32_t size_logical[2] = {0, 0};
+ bool has_size_logical = false;
+
+ int32_t position_logical[2] = {0, 0};
+ bool has_position_logical = false;
+
+ int transform = 0;
+ int scale = 1;
+ /**
+ * The integer `scale` value should be used in almost all cases,
+ * as this is what is used for most API calls.
+ * Only use fractional scaling to calculate the DPI.
+ *
+ * \note Internally an #wl_fixed_t is used to store the scale of the display,
+ * so use the same value here (avoid floating point arithmetic in general).
+ */
+ wl_fixed_t scale_fractional = wl_fixed_from_int(1);
+ bool has_scale_fractional = false;
+
std::string make;
std::string model;
};
@@ -79,9 +100,9 @@ class GHOST_SystemWayland : public GHOST_System {
wl_compositor *compositor();
- xdg_wm_base *shell();
+ xdg_wm_base *xdg_shell();
- zxdg_decoration_manager_v1 *decoration_manager();
+ zxdg_decoration_manager_v1 *xdg_decoration_manager();
const std::vector<output_t *> &outputs() const;
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 68d50c597d6..fdd372a9bd4 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -20,8 +20,8 @@
static constexpr size_t base_dpi = 96;
struct window_t {
- GHOST_WindowWayland *w;
- wl_surface *surface;
+ GHOST_WindowWayland *w = nullptr;
+ struct wl_surface *wl_surface = nullptr;
/**
* Outputs on which the window is currently shown on.
*
@@ -31,22 +31,27 @@ struct window_t {
std::vector<const output_t *> outputs;
/** The scale value written to #wl_surface_set_buffer_scale. */
- int scale;
- /** The DPI (currently always `scale * base_dpi`). */
- uint16_t dpi;
+ int scale = 0;
+ /**
+ * The DPI, either:
+ * - `scale * base_dpi`
+ * - `wl_fixed_to_int(scale_fractional * base_dpi)`
+ * When fractional scaling is available.
+ */
+ uint32_t dpi = 0;
- struct xdg_surface *xdg_surface;
- struct xdg_toplevel *xdg_toplevel;
+ struct xdg_surface *xdg_surface = nullptr;
+ struct xdg_toplevel *xdg_toplevel = nullptr;
struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr;
- enum zxdg_toplevel_decoration_v1_mode decoration_mode;
- wl_egl_window *egl_window;
- bool is_maximised;
- bool is_fullscreen;
- bool is_active;
- bool is_dialog;
-
- int32_t size[2];
- int32_t size_pending[2];
+ enum zxdg_toplevel_decoration_v1_mode decoration_mode = (enum zxdg_toplevel_decoration_v1_mode)0;
+ wl_egl_window *egl_window = nullptr;
+ bool is_maximised = false;
+ bool is_fullscreen = false;
+ bool is_active = false;
+ bool is_dialog = false;
+
+ int32_t size[2] = {0, 0};
+ int32_t size_pending[2] = {0, 0};
};
/* -------------------------------------------------------------------- */
@@ -54,25 +59,42 @@ struct window_t {
* \{ */
static int outputs_max_scale_or_default(const std::vector<output_t *> &outputs,
- const int scale_default)
+ const int32_t scale_default,
+ uint32_t *r_dpi)
{
int scale_max = 0;
+ const output_t *output_max = nullptr;
for (const output_t *reg_output : outputs) {
- scale_max = std::max(scale_max, reg_output->scale);
+ if (scale_max < reg_output->scale) {
+ scale_max = reg_output->scale;
+ output_max = reg_output;
+ }
+ }
+
+ if (scale_max != 0) {
+ if (r_dpi) {
+ *r_dpi = output_max->has_scale_fractional ?
+ /* Fractional DPI. */
+ wl_fixed_to_int(output_max->scale_fractional * base_dpi) :
+ /* Simple non-fractional DPI. */
+ (scale_max * base_dpi);
+ }
+ return scale_max;
+ }
+
+ if (r_dpi) {
+ *r_dpi = scale_default * base_dpi;
}
- return scale_max ? scale_max : scale_default;
+ return scale_default;
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Wayland Interface Callbacks
- *
- * These callbacks are registered for Wayland interfaces and called when
- * an event is received from the compositor.
+/** \name Listener (XDG Top Level), #xdg_toplevel_listener
* \{ */
-static void toplevel_configure(
+static void xdg_toplevel_handle_configure(
void *data, xdg_toplevel * /*xdg_toplevel*/, int32_t width, int32_t height, wl_array *states)
{
window_t *win = static_cast<window_t *>(data);
@@ -105,17 +127,23 @@ static void toplevel_configure(
}
}
-static void toplevel_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
+static void xdg_toplevel_handle_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
{
static_cast<window_t *>(data)->w->close();
}
static const xdg_toplevel_listener toplevel_listener = {
- toplevel_configure,
- toplevel_close,
+ xdg_toplevel_handle_configure,
+ xdg_toplevel_handle_close,
};
-static void toplevel_decoration_configure(
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Decoration Listener), #zxdg_toplevel_decoration_v1_listener
+ * \{ */
+
+static void xdg_toplevel_decoration_handle_configure(
void *data,
struct zxdg_toplevel_decoration_v1 * /*zxdg_toplevel_decoration_v1*/,
uint32_t mode)
@@ -124,10 +152,16 @@ static void toplevel_decoration_configure(
}
static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = {
- toplevel_decoration_configure,
+ xdg_toplevel_decoration_handle_configure,
};
-static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Surface Handle Configure), #xdg_surface_listener
+ * \{ */
+
+static void xdg_surface_handle_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
{
window_t *win = static_cast<window_t *>(data);
@@ -154,11 +188,19 @@ static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t ser
xdg_surface_ack_configure(xdg_surface, serial);
}
-static const xdg_surface_listener surface_listener = {
- surface_configure,
+static const xdg_surface_listener xdg_surface_listener = {
+ xdg_surface_handle_configure,
};
-static void surface_enter(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Surface), #wl_surface_listener
+ * \{ */
+
+static void surface_handle_enter(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
output_t *reg_output = w->output_find_by_wl(output);
@@ -175,7 +217,9 @@ static void surface_enter(void *data, struct wl_surface * /*wl_surface*/, struct
w->outputs_changed_update_scale();
}
-static void surface_leave(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output)
+static void surface_handle_leave(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
output_t *reg_output = w->output_find_by_wl(output);
@@ -193,8 +237,8 @@ static void surface_leave(void *data, struct wl_surface * /*wl_surface*/, struct
}
struct wl_surface_listener wl_surface_listener = {
- surface_enter,
- surface_leave,
+ surface_handle_enter,
+ surface_handle_leave,
};
/** \} */
@@ -242,18 +286,17 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
*
* Using the maximum scale is best as it results in the window first being smaller,
* avoiding a large window flashing before it's made smaller. */
- w->scale = outputs_max_scale_or_default(this->m_system->outputs(), 1);
- w->dpi = w->scale * base_dpi;
+ w->scale = outputs_max_scale_or_default(this->m_system->outputs(), 1, &w->dpi);
/* Window surfaces. */
- w->surface = wl_compositor_create_surface(m_system->compositor());
+ w->wl_surface = wl_compositor_create_surface(m_system->compositor());
wl_surface_set_buffer_scale(this->surface(), w->scale);
- wl_surface_add_listener(w->surface, &wl_surface_listener, this);
+ wl_surface_add_listener(w->wl_surface, &wl_surface_listener, this);
- w->egl_window = wl_egl_window_create(w->surface, int(w->size[0]), int(w->size[1]));
+ w->egl_window = wl_egl_window_create(w->wl_surface, int(w->size[0]), int(w->size[1]));
- w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface);
+ w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->xdg_shell(), w->wl_surface);
w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
/* NOTE: The limit is in points (not pixels) so Hi-DPI will limit to larger number of pixels.
@@ -262,18 +305,18 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
* when the `w->scale` changed. */
xdg_toplevel_set_min_size(w->xdg_toplevel, 320, 240);
- if (m_system->decoration_manager()) {
+ if (m_system->xdg_decoration_manager()) {
w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
- m_system->decoration_manager(), w->xdg_toplevel);
+ m_system->xdg_decoration_manager(), w->xdg_toplevel);
zxdg_toplevel_decoration_v1_add_listener(
w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w);
zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
- wl_surface_set_user_data(w->surface, this);
+ wl_surface_set_user_data(w->wl_surface, this);
- xdg_surface_add_listener(w->xdg_surface, &surface_listener, w);
+ xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
if (parentWindow && is_dialog) {
@@ -282,7 +325,7 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
}
/* Call top-level callbacks. */
- wl_surface_commit(w->surface);
+ wl_surface_commit(w->wl_surface);
wl_display_roundtrip(m_system->display());
#ifdef GHOST_OPENGL_ALPHA
@@ -336,7 +379,7 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size()
wl_surface *GHOST_WindowWayland::surface() const
{
- return w->surface;
+ return w->wl_surface;
}
std::vector<const output_t *> &GHOST_WindowWayland::outputs()
@@ -347,7 +390,7 @@ std::vector<const output_t *> &GHOST_WindowWayland::outputs()
output_t *GHOST_WindowWayland::output_find_by_wl(struct wl_output *output)
{
for (output_t *reg_output : this->m_system->outputs()) {
- if (reg_output->output == output) {
+ if (reg_output->wl_output == output) {
return reg_output;
}
}
@@ -356,28 +399,35 @@ output_t *GHOST_WindowWayland::output_find_by_wl(struct wl_output *output)
bool GHOST_WindowWayland::outputs_changed_update_scale()
{
- const int scale_next = outputs_max_scale_or_default(this->m_system->outputs(), 0);
+ uint32_t dpi_next;
+ const int scale_next = outputs_max_scale_or_default(this->m_system->outputs(), 0, &dpi_next);
if (scale_next == 0) {
return false;
}
+
window_t *win = this->w;
+ const uint32_t dpi_curr = win->dpi;
const int scale_curr = win->scale;
- if (scale_next == scale_curr) {
- return false;
- }
+ bool changed = false;
- /* Unlikely but possible there is a pending size change is set. */
- win->size_pending[0] = (win->size_pending[0] / scale_curr) * scale_next;
- win->size_pending[1] = (win->size_pending[1] / scale_curr) * scale_next;
+ if (scale_next != scale_curr) {
+ /* Unlikely but possible there is a pending size change is set. */
+ win->size_pending[0] = (win->size_pending[0] / scale_curr) * scale_next;
+ win->size_pending[1] = (win->size_pending[1] / scale_curr) * scale_next;
- win->scale = scale_next;
- wl_surface_set_buffer_scale(this->surface(), scale_next);
+ win->scale = scale_next;
+ wl_surface_set_buffer_scale(this->surface(), scale_next);
+ changed = true;
+ }
- /* Using the real DPI will cause wrong scaling of the UI
- * use a multiplier for the default DPI as workaround. */
- win->dpi = scale_next * base_dpi;
+ if (dpi_next != dpi_curr) {
+ /* Using the real DPI will cause wrong scaling of the UI
+ * use a multiplier for the default DPI as workaround. */
+ win->dpi = dpi_next;
+ changed = true;
+ }
- return true;
+ return changed;
}
uint16_t GHOST_WindowWayland::dpi()
@@ -392,7 +442,7 @@ int GHOST_WindowWayland::scale()
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
{
- return m_system->setCursorGrab(mode, m_cursorGrab, w->surface);
+ return m_system->setCursorGrab(mode, m_cursorGrab, w->wl_surface);
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
@@ -484,7 +534,7 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
}
xdg_toplevel_destroy(w->xdg_toplevel);
xdg_surface_destroy(w->xdg_surface);
- wl_surface_destroy(w->surface);
+ wl_surface_destroy(w->wl_surface);
delete w;
}
diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h
index 8fec725e122..d7cd6608556 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.h
+++ b/intern/ghost/intern/GHOST_WindowWayland.h
@@ -17,7 +17,6 @@ class GHOST_SystemWayland;
struct output_t;
struct window_t;
-struct wl_surface;
class GHOST_WindowWayland : public GHOST_Window {
public:
@@ -102,7 +101,7 @@ class GHOST_WindowWayland : public GHOST_Window {
GHOST_TSuccess notify_size();
- wl_surface *surface() const;
+ struct wl_surface *surface() const;
std::vector<const output_t *> &outputs();
diff --git a/release/datafiles/icons/ops.curves.density.dat b/release/datafiles/icons/ops.curves.sculpt_density.dat
index f336de79082..f336de79082 100644
--- a/release/datafiles/icons/ops.curves.density.dat
+++ b/release/datafiles/icons/ops.curves.sculpt_density.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.slide.dat b/release/datafiles/icons/ops.curves.sculpt_slide.dat
index 7f143ad92cc..7f143ad92cc 100644
--- a/release/datafiles/icons/ops.curves.slide.dat
+++ b/release/datafiles/icons/ops.curves.sculpt_slide.dat
Binary files differ
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 21fa1e88627..f61d8465952 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -5588,6 +5588,17 @@ def km_font(params):
return keymap
+# Curves edit mode.
+def km_curves(params):
+ items = []
+ keymap = (
+ "Curves",
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
+ {"items": items},
+ )
+
+ return keymap
+
def km_sculpt_curves(params):
items = []
@@ -8013,6 +8024,7 @@ def generate_keymaps(params=None):
km_lattice(params),
km_particle(params),
km_font(params),
+ km_curves(params),
km_sculpt_curves(params),
km_object_non_modal(params),
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index d8d387036ff..a806e9e0c33 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -199,7 +199,8 @@ class CLIP_HT_header(Header):
row = layout.row(align=True)
row.prop(dopesheet, "sort_method", text="")
row.prop(dopesheet, "use_invert_sort",
- text="Invert", toggle=True)
+ text="", toggle=True,
+ icon='SORT_DESC' if dopesheet.use_invert_sort else 'SORT_ASC')
def _draw_masking(self, context):
layout = self.layout
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 5755ddb3018..13eefd27bec 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -64,7 +64,7 @@ bool BKE_id_attribute_remove(struct ID *id, const char *name, struct ReportList
* Creates a duplicate attribute layer.
*/
struct CustomDataLayer *BKE_id_attribute_duplicate(struct ID *id,
- struct CustomDataLayer *layer,
+ const char *name,
struct ReportList *reports);
struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
@@ -72,7 +72,7 @@ struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
int type,
eAttrDomain domain);
-struct CustomDataLayer *BKE_id_attribute_search(const struct ID *id,
+struct CustomDataLayer *BKE_id_attribute_search(struct ID *id,
const char *name,
eCustomDataMask type,
eAttrDomainMask domain_mask);
diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h
index 4ad17610207..271026d4253 100644
--- a/source/blender/blenkernel/BKE_subdiv_modifier.h
+++ b/source/blender/blenkernel/BKE_subdiv_modifier.h
@@ -7,6 +7,8 @@
#pragma once
+#include "BKE_subdiv.h"
+
#include "BLI_sys_types.h"
#ifdef __cplusplus
@@ -24,9 +26,30 @@ struct Subdiv;
struct SubdivSettings;
struct SubsurfModifierData;
-void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
- const struct SubsurfModifierData *smd,
- bool use_render_params);
+/* Runtime subsurf modifier data, cached in modifier on evaluated meshes. */
+typedef struct SubsurfRuntimeData {
+ /* Subdivision settings, exists before descriptor or mesh wrapper is created. */
+ SubdivSettings settings;
+
+ /* Cached subdivision surface descriptor, with topology and settings. */
+ struct Subdiv *subdiv;
+ bool set_by_draw_code;
+
+ /* Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */
+ bool has_gpu_subdiv;
+ int resolution;
+ bool use_optimal_display;
+ bool calc_loop_normals;
+ bool use_loop_normals;
+
+ /* Cached from the draw code for stats display. */
+ int stats_totvert;
+ int stats_totedge;
+ int stats_totpoly;
+ int stats_totloop;
+} SubsurfRuntimeData;
+
+bool BKE_subsurf_modifier_runtime_init(struct SubsurfModifierData *smd, bool use_render_params);
bool BKE_subsurf_modifier_use_custom_loop_normals(const struct SubsurfModifierData *smd,
const struct Mesh *mesh);
@@ -57,12 +80,7 @@ extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
* which matches settings and topology.
*/
struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(
- const struct SubsurfModifierData *smd,
- const struct SubdivSettings *subdiv_settings,
- const struct Mesh *mesh,
- bool for_draw_code);
-
-struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd);
+ struct SubsurfRuntimeData *runtime_data, const struct Mesh *mesh, bool for_draw_code);
/**
* Return the #ModifierMode required for the evaluation of the subsurf modifier,
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 8496692ceb3..b3a9d894944 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -52,6 +52,7 @@
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
+#include "BKE_subdiv_modifier.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -598,10 +599,10 @@ static bool mesh_has_modifier_final_normals(const Mesh *mesh_input,
/* Test if mesh has the required loop normals, in case an additional modifier
* evaluation from another instance or from an operator requests it but the
* initial normals were not loop normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- return (!do_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
+ return (!calc_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
}
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
@@ -610,16 +611,19 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
Mesh *mesh_final)
{
/* Compute normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). In case
* of deferred CPU subdivision, this will be computed when the wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
@@ -1266,15 +1270,18 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
return;
}
- const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals. In case of deferred CPU subdivision, this will be computed when the
* wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc
index b2ea8b833b3..7c09b4a4ce3 100644
--- a/source/blender/blenkernel/intern/attribute.cc
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -208,53 +208,36 @@ CustomDataLayer *BKE_id_attribute_new(
return (index == -1) ? nullptr : &(customdata->layers[index]);
}
-CustomDataLayer *BKE_id_attribute_duplicate(ID *id, CustomDataLayer *layer, ReportList *reports)
+CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList *reports)
{
- DomainInfo info[ATTR_DOMAIN_NUM];
- get_domains(id, info);
-
- eCustomDataType type = (eCustomDataType)layer->type;
- eAttrDomain domain = BKE_id_attribute_domain(id, layer);
-
- CustomData *customdata = info[domain].customdata;
- if (customdata == nullptr) {
- BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
+ const CustomDataLayer *src_layer = BKE_id_attribute_search(
+ id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ if (src_layer == nullptr) {
+ BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
return nullptr;
}
- char name[MAX_CUSTOMDATA_LAYER_NAME];
- char uniquename[MAX_CUSTOMDATA_LAYER_NAME];
+ const eCustomDataType type = (eCustomDataType)src_layer->type;
+ const eAttrDomain domain = BKE_id_attribute_domain(id, src_layer);
/* Make a copy of name in case CustomData API reallocates the layers. */
- BLI_strncpy(name, layer->name, MAX_CUSTOMDATA_LAYER_NAME);
- BKE_id_attribute_calc_unique_name(id, layer->name, uniquename);
+ const std::string name_copy = name;
- switch (GS(id->name)) {
- case ID_ME: {
- Mesh *me = (Mesh *)id;
- BMEditMesh *em = me->edit_mesh;
- if (em != nullptr) {
- BM_data_layer_add_named(em->bm, customdata, type, uniquename);
- }
- else {
- CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
- }
- break;
- }
- default: {
- CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
- break;
- }
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+ CustomData *customdata = info[domain].customdata;
+
+ CustomDataLayer *new_layer = BKE_id_attribute_new(id, name_copy.c_str(), type, domain, reports);
+ if (new_layer == nullptr) {
+ return nullptr;
}
- int from_index = CustomData_get_named_layer_index(customdata, type, name);
- int to_index = CustomData_get_named_layer_index(customdata, type, uniquename);
+ const int from_index = CustomData_get_named_layer_index(customdata, type, name_copy.c_str());
+ const int to_index = CustomData_get_named_layer_index(customdata, type, new_layer->name);
CustomData_copy_data_layer(
customdata, customdata, from_index, to_index, 0, 0, info[domain].length);
- return (to_index == -1) ? nullptr : &(customdata->layers[to_index]);
+ return new_layer;
}
bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
@@ -317,7 +300,7 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
return nullptr;
}
-CustomDataLayer *BKE_id_attribute_search(const ID *id,
+CustomDataLayer *BKE_id_attribute_search(ID *id,
const char *name,
const eCustomDataMask type_mask,
const eAttrDomainMask domain_mask)
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc
index c505a74724b..fdebf1d6a26 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.cc
+++ b/source/blender/blenkernel/intern/mesh_wrapper.cc
@@ -314,28 +314,23 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
return me;
}
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data == nullptr || runtime_data->settings.level == 0) {
+ return me;
+ }
+
/* Initialize the settings before ensuring the descriptor as this is checked to decide whether
* subdivision is needed at all, and checking the descriptor status might involve checking if the
* data is out-of-date, which is a very expensive operation. */
SubdivToMeshSettings mesh_settings;
- mesh_settings.resolution = me->runtime.subsurf_resolution;
- mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display;
+ mesh_settings.resolution = runtime_data->resolution;
+ mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
if (mesh_settings.resolution < 3) {
return me;
}
- const bool apply_render = me->runtime.subsurf_apply_render;
-
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render);
- if (subdiv_settings.level == 0) {
- return me;
- }
-
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, me, false);
if (subdiv == nullptr) {
/* Happens on bad topology, but also on empty input mesh. */
return me;
@@ -358,7 +353,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
CustomData_set_layer_flag(&me->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
CustomData_set_layer_flag(&subdiv_mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- else if (me->runtime.subsurf_do_loop_normals) {
+ else if (runtime_data->calc_loop_normals) {
BKE_mesh_calc_normals_split(subdiv_mesh);
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index a5f6c453ed4..8f54d71108a 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -244,24 +244,42 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const
}
}
-static void update_active_strip_from_listbase(AnimData *adt_dest,
- NlaTrack *track_dest,
- const NlaStrip *active_strip,
- const ListBase /* NlaStrip */ *strips_source)
+/**
+ * Find `active_strip` in `strips_source`, then return the strip with the same
+ * index from `strips_dest`.
+ */
+static NlaStrip *find_active_strip_from_listbase(const NlaStrip *active_strip,
+ const ListBase /* NlaStrip */ *strips_source,
+ const ListBase /* NlaStrip */ *strips_dest)
{
- NlaStrip *strip_dest = track_dest->strips.first;
+ NlaStrip *strip_dest = strips_dest->first;
LISTBASE_FOREACH (const NlaStrip *, strip_source, strips_source) {
- if (strip_source == active_strip) {
- adt_dest->actstrip = strip_dest;
- return;
+ if (strip_dest == NULL) {
+ /* The tracks are assumed to have an equal number of strips, but this is not the case when
+ * dragging multiple strips. The transform system merges the selected strips into one
+ * meta-strip, reducing the number of strips in `track_dest`. */
+ break;
}
-
- if (strip_source->type == NLASTRIP_TYPE_META) {
- update_active_strip_from_listbase(adt_dest, track_dest, active_strip, &strip_source->strips);
+ if (strip_source == active_strip) {
+ return strip_dest;
+ }
+
+ const bool src_is_meta = strip_source->type == NLASTRIP_TYPE_META;
+ const bool dst_is_meta = strip_dest->type == NLASTRIP_TYPE_META;
+ BLI_assert_msg(src_is_meta == dst_is_meta,
+ "Expecting topology of source and destination strips to be equal");
+ if (src_is_meta && dst_is_meta) {
+ NlaStrip *found_in_meta = find_active_strip_from_listbase(
+ active_strip, &strip_source->strips, &strip_dest->strips);
+ if (found_in_meta != NULL) {
+ return found_in_meta;
+ }
}
strip_dest = strip_dest->next;
}
+
+ return NULL;
}
/* Set adt_dest->actstrip to the strip with the same index as adt_source->actstrip. */
@@ -272,8 +290,9 @@ static void update_active_strip(AnimData *adt_dest,
{
BLI_assert(BLI_listbase_count(&track_source->strips) == BLI_listbase_count(&track_dest->strips));
- update_active_strip_from_listbase(
- adt_dest, track_dest, adt_source->actstrip, &track_source->strips);
+ NlaStrip *active_strip = find_active_strip_from_listbase(
+ adt_source->actstrip, &track_source->strips, &track_dest->strips);
+ adt_dest->actstrip = active_strip;
}
/* Set adt_dest->act_track to the track with the same index as adt_source->act_track. */
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 3a69a33105e..3b20bdc826c 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1391,7 +1391,7 @@ void pbvh_free_draw_buffers(PBVH *pbvh, PBVHNode *node)
}
}
-static void pbvh_check_draw_layout(PBVH *pbvh, bool full_render)
+static void pbvh_check_draw_layout(PBVH *pbvh)
{
const CustomData *vdata;
const CustomData *ldata;
@@ -1419,8 +1419,14 @@ static void pbvh_check_draw_layout(PBVH *pbvh, bool full_render)
break;
}
- /* rebuild all draw buffers if attribute layout changed */
- if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, !full_render)) {
+ /* Rebuild all draw buffers if attribute layout changed.
+ *
+ * NOTE: The optimization where we only send active attributes
+ * to the GPU in workbench mode is disabled due to bugs
+ * (there's no guarantee there isn't another EEVEE viewport which would
+ * free the draw buffers and corrupt the draw cache).
+ */
+ if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, false)) {
/* attribute layout changed; force rebuild */
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *node = pbvh->nodes + i;
@@ -2861,7 +2867,7 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
void *user_data,
- bool full_render)
+ bool UNUSED(full_render))
{
PBVHNode **nodes;
int totnode;
@@ -2884,7 +2890,7 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
}
- pbvh_check_draw_layout(pbvh, full_render);
+ pbvh_check_draw_layout(pbvh);
/* Update draw buffers. */
if (totnode != 0 && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) {
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
index e43da956ce5..f5423dccc0f 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.c
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -3,8 +3,6 @@
#include "BKE_subdiv_modifier.h"
-#include "BLI_session_uuid.h"
-
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
@@ -21,22 +19,40 @@
#include "opensubdiv_capi.h"
-void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings,
- const SubsurfModifierData *smd,
- const bool use_render_params)
+bool BKE_subsurf_modifier_runtime_init(SubsurfModifierData *smd, const bool use_render_params)
{
const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
- settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
- settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
- settings->level = settings->is_simple ?
- 1 :
- (settings->is_adaptive ? smd->quality : requested_levels);
- settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
- settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
+ SubdivSettings settings;
+ settings.is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
+ settings.is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
+ settings.level = settings.is_simple ? 1 :
+ (settings.is_adaptive ? smd->quality : requested_levels);
+ settings.use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
+ settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
smd->boundary_smooth);
- settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
+ settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
smd->uv_smooth);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (settings.level == 0) {
+ /* Modifier is effectively disabled, but still update settings if runtime data
+ * was already allocated. */
+ if (runtime_data) {
+ runtime_data->settings = settings;
+ }
+
+ return false;
+ }
+ else {
+ /* Allocate runtime data if it did not exist yet. */
+ if (runtime_data == NULL) {
+ runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
+ smd->modifier.runtime = runtime_data;
+ }
+ runtime_data->settings = settings;
+ return true;
+ }
}
static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
@@ -133,37 +149,27 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
- return BLI_session_uuid_is_generated(&mesh->runtime.subsurf_session_uuid);
+ SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ return runtime_data && runtime_data->has_gpu_subdiv;
}
void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL;
-Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd,
- const SubdivSettings *subdiv_settings,
+Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,
const Mesh *mesh,
const bool for_draw_code)
{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) {
BKE_subdiv_free(runtime_data->subdiv);
runtime_data->subdiv = NULL;
}
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(
+ runtime_data->subdiv, &runtime_data->settings, mesh);
runtime_data->subdiv = subdiv;
runtime_data->set_by_draw_code = for_draw_code;
return subdiv;
}
-SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(SubsurfModifierData *smd)
-{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
- if (runtime_data == NULL) {
- runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
- smd->modifier.runtime = runtime_data;
- }
- return runtime_data;
-}
-
int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode)
{
if (is_final_render) {
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index f9d3a44e5cb..3506d0e347a 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -336,6 +336,10 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
+ /* Descending order of average error: tracks with the highest error are on top. */
+ tracking->dopesheet.sort_method = TRACKING_DOPE_SORT_AVERAGE_ERROR;
+ tracking->dopesheet.flag |= TRACKING_DOPE_SORT_INVERSE;
+
BKE_tracking_object_add(tracking, "Camera");
}
@@ -2904,6 +2908,10 @@ static int channels_average_error_sort(const void *a, const void *b)
return 1;
}
+ if (channel_a->track->error == channel_b->track->error) {
+ return channels_alpha_sort(a, b);
+ }
+
return 0;
}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
index 280b31ea463..c0d4393f2da 100644
--- a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
@@ -5,6 +5,6 @@ void main()
vec3 world_pos = point_object_to_world(vec3(au, 0.0));
gl_Position = point_world_to_ndc(world_pos);
- finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorVertexSelect : vec4(colorWire.rgb, 1.0);
+ finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorFaceDot : vec4(colorWire.rgb, 1.0);
gl_PointSize = pointSize;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index 2c07b651c7c..992ffe16a14 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -163,7 +163,7 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
cache->is_dirty = true;
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
@@ -530,8 +530,6 @@ static bool curves_ensure_attributes(const Curves &curves,
}
switch (type) {
- default:
- break;
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
@@ -548,6 +546,8 @@ static bool curves_ensure_attributes(const Curves &curves,
}
break;
}
+ default:
+ break;
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc
index 96b5910072b..7c02ee2c033 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc
@@ -2068,8 +2068,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
if (do_subdivision) {
- DRW_create_subdivision(scene,
- ob,
+ DRW_create_subdivision(ob,
me,
cache,
&cache->final,
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 2b0953b0b9b..b37a420b555 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -1052,14 +1052,10 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
Subdiv *subdiv,
Mesh *mesh_eval,
- const Scene *scene,
- const SubsurfModifierData *smd,
- const bool is_final_render)
+ const SubsurfRuntimeData *runtime_data)
{
- const int requested_levels = (is_final_render) ? smd->renderLevels : smd->levels;
- const int level = get_render_subsurf_level(&scene->r, requested_levels, is_final_render);
SubdivToMeshSettings to_mesh_settings;
- to_mesh_settings.resolution = (1 << level) + 1;
+ to_mesh_settings.resolution = runtime_data->resolution;
to_mesh_settings.use_optimal_display = false;
if (cache->resolution != to_mesh_settings.resolution) {
@@ -2006,8 +2002,7 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
MEM_freeN(per_polygon_mat_offset);
}
-static bool draw_subdiv_create_requested_buffers(const Scene *scene,
- Object *ob,
+static bool draw_subdiv_create_requested_buffers(Object *ob,
Mesh *mesh,
struct MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
@@ -2021,16 +2016,10 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const bool use_hide,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(
- BKE_modifiers_findby_session_uuid(ob, &mesh->runtime.subsurf_session_uuid));
- BLI_assert(smd);
+ SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ BLI_assert(runtime_data && runtime_data->has_gpu_subdiv);
- const bool is_final_render = DRW_state_is_scene_render();
-
- SubdivSettings settings;
- BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render);
-
- if (settings.level == 0) {
+ if (runtime_data->settings.level == 0) {
return false;
}
@@ -2041,9 +2030,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
bm = mesh->edit_mesh->bm;
}
- BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true);
if (!subdiv) {
return false;
}
@@ -2064,13 +2051,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
}
DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
- if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) {
+ if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, runtime_data)) {
return false;
}
/* Edges which do not come from coarse edges should not be drawn in edit mode, only in object
* mode when optimal display in turned off. */
- const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges) || is_editmode;
+ const bool optimal_display = runtime_data->use_optimal_display || is_editmode;
draw_cache->bm = bm;
draw_cache->mesh = mesh_eval;
@@ -2078,14 +2065,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
draw_cache->optimal_display = optimal_display;
draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
- /* Copy topology information for stats display. Use `mesh` directly, as `mesh_eval` could be the
- * edit mesh. */
- mesh->runtime.subsurf_totvert = draw_cache->num_subdiv_verts;
- mesh->runtime.subsurf_totedge = draw_cache->num_subdiv_edges;
- mesh->runtime.subsurf_totpoly = draw_cache->num_subdiv_quads;
- mesh->runtime.subsurf_totloop = draw_cache->num_subdiv_loops;
+ /* Copy topology information for stats display. */
+ runtime_data->stats_totvert = draw_cache->num_subdiv_verts;
+ runtime_data->stats_totedge = draw_cache->num_subdiv_edges;
+ runtime_data->stats_totpoly = draw_cache->num_subdiv_quads;
+ runtime_data->stats_totloop = draw_cache->num_subdiv_loops;
- draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
+ draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) &&
(mesh_eval->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh_eval->ldata,
CD_CUSTOMLOOPNORMAL);
@@ -2207,8 +2193,7 @@ blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWS
static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
-void DRW_create_subdivision(const Scene *scene,
- Object *ob,
+void DRW_create_subdivision(Object *ob,
Mesh *mesh,
struct MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
@@ -2231,8 +2216,7 @@ void DRW_create_subdivision(const Scene *scene,
const double begin_time = PIL_check_seconds_timer();
#endif
- if (!draw_subdiv_create_requested_buffers(scene,
- ob,
+ if (!draw_subdiv_create_requested_buffers(ob,
mesh,
batch_cache,
mbc,
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index 8920a2dcd51..2d9f4713feb 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -185,8 +185,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache);
/** \} */
-void DRW_create_subdivision(const struct Scene *scene,
- struct Object *ob,
+void DRW_create_subdivision(struct Object *ob,
struct Mesh *mesh,
struct MeshBatchCache *batch_cache,
struct MeshBufferCache *mbc,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index 5f07f8dfb72..fb6b5e1904b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -27,21 +27,16 @@ namespace blender::draw {
static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDomain domain)
{
switch (domain) {
- default: {
- return nullptr;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata;
- }
+ default:
+ return nullptr;
}
}
@@ -50,7 +45,7 @@ static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDom
* etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4
* in the shader.
*/
-template<typename AttributeType, typename VBOType> struct attribute_type_converter {
+template<typename AttributeType, typename VBOType> struct AttributeTypeConverter {
static VBOType convert_value(AttributeType value)
{
if constexpr (std::is_same_v<AttributeType, VBOType>) {
@@ -67,7 +62,7 @@ struct gpuMeshCol {
ushort r, g, b, a;
};
-template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
+template<> struct AttributeTypeConverter<MPropCol, gpuMeshCol> {
static gpuMeshCol convert_value(MPropCol value)
{
gpuMeshCol result;
@@ -86,53 +81,42 @@ static uint gpu_component_size_for_attribute_type(eCustomDataType type)
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
/* TODO(@kevindietrich): should be 1 when scalar attributes conversion is handled by us. See
* comment #extract_attr_init. */
return 3;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
return 2;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
return 3;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return 4;
- }
- default: {
+ default:
return 0;
- }
}
}
static GPUVertFetchMode get_fetch_mode_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_FETCH_INT_TO_FLOAT;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_FETCH_INT_TO_FLOAT_UNIT;
- }
- default: {
+ default:
return GPU_FETCH_FLOAT;
- }
}
}
static GPUVertCompType get_comp_type_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_COMP_I32;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_COMP_U16;
- }
- default: {
+ default:
return GPU_COMP_F32;
- }
}
}
@@ -184,41 +168,36 @@ static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
const AttributeType *attr_data = static_cast<const AttributeType *>(
CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
switch (request.domain) {
- default: {
- BLI_assert(false);
- break;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
- *vbo_data = converter::convert_value(attr_data[mloop->v]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->v]);
}
break;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) {
- *vbo_data = converter::convert_value(attr_data[ml_index]);
+ *vbo_data = Converter::convert_value(attr_data[ml_index]);
}
break;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) {
- *vbo_data = converter::convert_value(attr_data[mloop->e]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->e]);
}
break;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
const MPoly &poly = mpoly[mp_index];
- const VBOType value = converter::convert_value(attr_data[mp_index]);
+ const VBOType value = Converter::convert_value(attr_data[mp_index]);
for (int l = 0; l < poly.totloop; l++) {
*vbo_data++ = value;
}
}
break;
- }
+ default:
+ BLI_assert_unreachable();
+ break;
}
}
@@ -231,9 +210,9 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
BLI_assert(custom_data);
const int layer_index = request.layer_index;
- int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
+ const int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
BMIter f_iter;
BMFace *efa;
@@ -255,10 +234,10 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs));
}
else {
- BLI_assert(false);
+ BLI_assert_unreachable();
continue;
}
- *vbo_data = converter::convert_value(*attr_data);
+ *vbo_data = Converter::convert_value(*attr_data);
vbo_data++;
} while ((l_iter = l_iter->next) != l_first);
}
@@ -297,37 +276,29 @@ static void extract_attr_init(const MeshRenderData *mr,
* Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar
* texture as for volume attribute, so we can control the conversion ourselves. */
switch (request.cd_type) {
- case CD_PROP_BOOL: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, vbo, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
}
@@ -353,37 +324,29 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop));
switch (request.cd_type) {
- case CD_PROP_BOOL: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, src_data, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
@@ -430,7 +393,7 @@ EXTRACT_INIT_WRAPPER(12)
EXTRACT_INIT_WRAPPER(13)
EXTRACT_INIT_WRAPPER(14)
-template<int index>
+template<int Index>
constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn)
{
MeshExtract extractor = {nullptr};
@@ -439,7 +402,7 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
- extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]);
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[Index]);
return extractor;
}
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 34ae7697d2d..a7abaab88ff 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -772,17 +772,17 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curve.pen
ops.curve.radius
ops.curve.vertex_random
- ops.curves.density
ops.curves.sculpt_add
ops.curves.sculpt_comb
ops.curves.sculpt_cut
ops.curves.sculpt_delete
+ ops.curves.sculpt_density
ops.curves.sculpt_grow_shrink
ops.curves.sculpt_pinch
ops.curves.sculpt_puff
+ ops.curves.sculpt_slide
ops.curves.sculpt_smooth
ops.curves.sculpt_snake_hook
- ops.curves.slide
ops.generic.cursor
ops.generic.select
ops.generic.select_box
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 37ec7a61bcb..c7e782b7b89 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -518,15 +518,18 @@ static int geometry_color_attribute_duplicate_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
ID *id = static_cast<ID *>(ob->data);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
if (layer == nullptr) {
return OPERATOR_CANCELLED;
}
- CustomDataLayer *newLayer = BKE_id_attribute_duplicate(id, layer, op->reports);
+ CustomDataLayer *new_layer = BKE_id_attribute_duplicate(id, layer->name, op->reports);
+ if (new_layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
- BKE_id_attributes_active_color_set(id, newLayer);
+ BKE_id_attributes_active_color_set(id, new_layer);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
@@ -539,6 +542,10 @@ static bool geometry_color_attributes_duplicate_poll(bContext *C)
if (!geometry_attributes_poll(C)) {
return false;
}
+ if (CTX_data_edit_object(C) != nullptr) {
+ CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode");
+ return false;
+ }
Object *ob = ED_object_context(C);
ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 5ffcdbd9668..6d2f45813fe 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -2945,6 +2945,9 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
{
+ /* Caller should check. */
+ BLI_assert((but->flag & UI_BUT_DISABLED) == 0);
+
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
ui_textedit_string_set(but, but->active, value);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 60a68e270bf..aafb56119ae 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1942,6 +1942,24 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/** \name Drop Name Operator
* \{ */
+static bool drop_name_poll(bContext *C)
+{
+ if (!ED_operator_regionactive(C)) {
+ return false;
+ }
+
+ const uiBut *but = UI_but_active_drop_name_button(C);
+ if (!but) {
+ return false;
+ }
+
+ if (but->flag & UI_BUT_DISABLED) {
+ return false;
+ }
+
+ return true;
+}
+
static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiBut *but = UI_but_active_drop_name_button(C);
@@ -1961,7 +1979,7 @@ static void UI_OT_drop_name(wmOperatorType *ot)
ot->idname = "UI_OT_drop_name";
ot->description = "Drop name to button";
- ot->poll = ED_operator_regionactive;
+ ot->poll = drop_name_poll;
ot->invoke = drop_name_invoke;
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index a8eed136df3..4819ae09785 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -100,6 +100,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ export_params.export_colors = RNA_boolean_get(op->ptr, "export_colors");
export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
export_params.path_mode = RNA_enum_get(op->ptr, "path_mode");
export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
@@ -160,6 +161,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE);
uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_colors", 0, IFACE_("Colors"), ICON_NONE);
uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE);
uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
@@ -315,6 +317,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"Export Normals",
"Export per-face normals if the face is flat-shaded, per-face-per-loop "
"normals if smooth-shaded");
+ RNA_def_boolean(ot->srna, "export_colors", false, "Export Colors", "Export per-vertex colors");
RNA_def_boolean(ot->srna,
"export_materials",
true,
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 7c0b6fb0a93..e5fe108b6cd 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -364,12 +364,9 @@ static int select_exec(bContext *C, wmOperator *op)
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
if (deselect_all) {
- /* For clip editor tracks, leave deselect all to clip editor. */
- if (!ED_clip_can_select(C)) {
- ED_mask_deselect_all(C);
- ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
- }
+ ED_mask_deselect_all(C);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
return OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index bbfbbd2cc58..28e304bfa74 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -394,8 +394,6 @@ static int select_exec(bContext *C, wmOperator *op)
else if (deselect_all) {
ed_tracking_deselect_all_tracks(tracksbase);
ed_tracking_deselect_all_plane_tracks(plane_tracks_base);
- /* Mask as well if we are in combined mask / track view. */
- ED_mask_deselect_all(C);
}
ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index b817ff887ce..29a7eb150a1 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -46,6 +46,7 @@
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph_query.h"
@@ -92,15 +93,18 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st
}
int totvert, totedge, totface, totloop;
- if (me_eval->runtime.subdiv_ccg != nullptr) {
- const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+
+ const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+ const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data;
+
+ if (subdiv_ccg != nullptr) {
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
}
- else if (me_eval->runtime.subsurf_resolution != 0) {
- totvert = me_eval->runtime.subsurf_totvert;
- totedge = me_eval->runtime.subsurf_totedge;
- totface = me_eval->runtime.subsurf_totpoly;
- totloop = me_eval->runtime.subsurf_totloop;
+ else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) {
+ totvert = subsurf_runtime_data->stats_totvert;
+ totedge = subsurf_runtime_data->stats_totedge;
+ totface = subsurf_runtime_data->stats_totpoly;
+ totloop = subsurf_runtime_data->stats_totloop;
}
else {
totvert = me_eval->totvert;
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 475d02020d0..ec19e8d5e5b 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -222,13 +222,33 @@ static void unlink_action_fn(bContext *C,
}
static void unlink_material_fn(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
+ ReportList *reports,
Scene *UNUSED(scene),
TreeElement *te,
TreeStoreElem *tsep,
- TreeStoreElem *UNUSED(tselem),
+ TreeStoreElem *tselem,
void *UNUSED(user_data))
{
+ const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA);
+
+ if (!te_is_material) {
+ /* Just fail silently. Another element may be selected that is a material, we don't want to
+ * confuse users with an error in that case. */
+ return;
+ }
+
+ if (!tsep || !TSE_IS_REAL_ID(tsep)) {
+ /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE
+ * for example) so there's no data to unlink from. */
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Cannot unlink material '%s'. It's not clear which object or object-data it "
+ "should be unlinked from, there's no object or object-data as parent in the "
+ "Outliner tree",
+ tselem->id->name + 2);
+ return;
+ }
+
Material **matar = nullptr;
int a, totcol = 0;
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ea6d3351eaa..647d13a4d56 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -340,7 +340,7 @@ static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & SEQ_MARKER_TRANS) !=
0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
SEQ_collection_free(strip_col);
}
@@ -863,7 +863,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
}
SEQ_collection_free(strip_col);
@@ -913,7 +913,7 @@ static bool sequencer_add_movie_single_strip(bContext *C,
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
}
SEQ_collection_free(strip_col);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 75966d4f070..86c438c616e 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -581,21 +581,13 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
{
- /* Iterate in reverse so meta-strips are iterated after their children. */
for (int i = data->num_seq - 1; i >= 0; i--) {
Sequence *seq = data->seq_array[i];
- int endframe;
- /* Offset seq start. */
seq->start = data->ts[i].start + offset;
-
if (data->trim[i]) {
- /* Find the end-frame. */
- endframe = seq->start + seq->len;
-
- /* Compute the sequence offsets. */
- seq->endofs = endframe - SEQ_time_right_handle_frame_get(seq);
- seq->startofs = SEQ_time_left_handle_frame_get(seq) - seq->start;
+ seq->startofs = data->ts[i].startofs - offset;
+ seq->endofs = data->ts[i].endofs + offset;
}
}
@@ -2397,6 +2389,13 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq)
return;
}
+ /* Add curves for strips inside meta strip. */
+ if (seq->type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
+ sequencer_copy_animation(scene, meta_child);
+ }
+ }
+
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
if (fcurves == NULL) {
return;
@@ -2406,6 +2405,7 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq)
BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu));
}
GSET_FOREACH_END();
+
BLI_gset_free(fcurves, NULL);
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 68f04aab969..226b0f84f14 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -281,296 +281,21 @@ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips
}
}
-static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
-{
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if (seq->flag & SEQ_OVERLAP) {
- return true;
- }
- }
- return false;
-}
-
-static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
-{
- SeqCollection *collection = SEQ_collection_create(__func__);
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
-/* Query strips positioned after left edge of transformed strips bound-box. */
-static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips)
-{
- int minframe = MAXFRAME;
- {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(seq));
- }
- }
-
- SeqCollection *collection = SEQ_collection_create(__func__);
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(seq) >= minframe) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
static ListBase *seqbase_active_get(const TransInfo *t)
{
Editing *ed = SEQ_editing_get(t->scene);
return SEQ_active_seqbase_get(ed);
}
-/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
- * to overlap of transformed strips. */
-static void seq_transform_handle_expand_to_fit(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
-{
- ListBase *markers = &scene->markers;
-
- SeqCollection *right_side_strips = query_right_side_strips(seqbasep, transformed_strips);
-
- /* Temporarily move right side strips beyond timeline boundary. */
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
- seq->machine += MAXSEQ * 2;
- }
-
- /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
- * strips on left side. */
- SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
- SEQ_transform_seqbase_shuffle_time(
- standalone_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(standalone_strips);
-
- /* Move temporarily moved strips back to their original place and tag for shuffling. */
- SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
- seq->machine -= MAXSEQ * 2;
- }
- /* Shuffle again to displace strips on right side. Final effect shuffling is done in
- * SEQ_transform_handle_overlap. */
- SEQ_transform_seqbase_shuffle_time(
- right_side_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(right_side_strips);
-}
-
-static SeqCollection *query_overwrite_targets(ListBase *seqbasep,
- SeqCollection *transformed_strips)
-{
- SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
-
- Sequence *seq, *seq_transformed;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- bool does_overlap = false;
-
- SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
- /* Effects of transformed strips can be unselected. These must not be included. */
- if (seq == seq_transformed) {
- SEQ_collection_remove_strip(seq, collection);
- }
- if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) {
- does_overlap = true;
- }
- }
-
- if (!does_overlap) {
- SEQ_collection_remove_strip(seq, collection);
- }
- }
-
- return collection;
-}
-
-typedef enum eOvelapDescrition {
- /* No overlap. */
- STRIP_OVERLAP_NONE,
- /* Overlapping strip covers overlapped completely. */
- STRIP_OVERLAP_IS_FULL,
- /* Overlapping strip is inside overlapped. */
- STRIP_OVERLAP_IS_INSIDE,
- /* Partial overlap between 2 strips. */
- STRIP_OVERLAP_LEFT_SIDE,
- STRIP_OVERLAP_RIGHT_SIDE,
-} eOvelapDescrition;
-
-static eOvelapDescrition overlap_description_get(const Sequence *transformed,
- const Sequence *target)
-{
- if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
- SEQ_time_right_handle_frame_get(transformed) >= SEQ_time_right_handle_frame_get(target)) {
- return STRIP_OVERLAP_IS_FULL;
- }
- if (SEQ_time_left_handle_frame_get(transformed) > SEQ_time_left_handle_frame_get(target) &&
- SEQ_time_right_handle_frame_get(transformed) < SEQ_time_right_handle_frame_get(target)) {
- return STRIP_OVERLAP_IS_INSIDE;
- }
- if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
- SEQ_time_left_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
- return STRIP_OVERLAP_LEFT_SIDE;
- }
- if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_right_handle_frame_get(target) &&
- SEQ_time_right_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
- return STRIP_OVERLAP_RIGHT_SIDE;
- }
- return STRIP_OVERLAP_NONE;
-}
-
-/* Split strip in 3 parts, remove middle part and fit transformed inside. */
-static void seq_transform_handle_overwrite_split(Scene *scene,
- ListBase *seqbasep,
- const Sequence *transformed,
- Sequence *target)
-{
- /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
- * NULL here. */
- Main *bmain = NULL;
-
- Sequence *split_strip = SEQ_edit_strip_split(bmain,
- scene,
- seqbasep,
- target,
- SEQ_time_left_handle_frame_get(transformed),
- SEQ_SPLIT_SOFT,
- NULL);
- SEQ_edit_strip_split(bmain,
- scene,
- seqbasep,
- split_strip,
- SEQ_time_right_handle_frame_get(transformed),
- SEQ_SPLIT_SOFT,
- NULL);
- SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
- SEQ_edit_remove_flagged_sequences(scene, seqbasep);
-}
-
-/* Trim strips by adjusting handle position.
- * This is bit more complicated in case overlap happens on effect. */
-static void seq_transform_handle_overwrite_trim(Scene *scene,
- ListBase *seqbasep,
- const Sequence *transformed,
- Sequence *target,
- const eOvelapDescrition overlap)
-{
- SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain);
-
- /* Expand collection by adding all target's children, effects and their children. */
- if ((target->type & SEQ_TYPE_EFFECT) != 0) {
- SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain);
- }
-
- /* Trim all non effects, that have influence on effect length which is overlapping. */
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, targets) {
- if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
- continue;
- }
- if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
- SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(transformed));
- }
- else {
- BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
- SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(transformed));
- }
- }
- SEQ_collection_free(targets);
-}
-
-static void seq_transform_handle_overwrite(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips)
-{
- SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips);
- SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
-
- Sequence *target;
- Sequence *transformed;
- SEQ_ITERATOR_FOREACH (target, targets) {
- SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
- if (transformed->machine != target->machine) {
- continue;
- }
-
- const eOvelapDescrition overlap = overlap_description_get(transformed, target);
-
- if (overlap == STRIP_OVERLAP_IS_FULL) {
- SEQ_collection_append_strip(target, strips_to_delete);
- }
- else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
- seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
- }
- else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
- seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
- }
- }
- }
-
- SEQ_collection_free(targets);
-
- /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()`
- * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */
- if (SEQ_collection_len(strips_to_delete) > 0) {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips_to_delete) {
- SEQ_edit_flag_for_removal(scene, seqbasep, seq);
- }
- SEQ_edit_remove_flagged_sequences(scene, seqbasep);
- }
- SEQ_collection_free(strips_to_delete);
-}
-
-static void seq_transform_handle_overlap_shuffle(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
-{
- ListBase *markers = &scene->markers;
-
- /* Shuffle non strips with no effects attached. */
- SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
- SEQ_transform_seqbase_shuffle_time(
- standalone_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(standalone_strips);
-}
-
-void SEQ_transform_handle_overlap(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
+static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
{
- const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
-
- switch (overlap_mode) {
- case SEQ_OVERLAP_EXPAND:
- seq_transform_handle_expand_to_fit(scene, seqbasep, transformed_strips, use_sync_markers);
- break;
- case SEQ_OVERLAP_OVERWRITE:
- seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
- break;
- case SEQ_OVERLAP_SHUFFLE:
- seq_transform_handle_overlap_shuffle(scene, seqbasep, transformed_strips, use_sync_markers);
- break;
- }
-
- /* If any effects still overlap, we need to move them up.
- * In some cases other strips can be overlapping still, see T90646. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if (SEQ_transform_test_overlap(seqbasep, seq)) {
- SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ if (seq->flag & SEQ_OVERLAP) {
+ return true;
}
- seq->flag &= ~SEQ_OVERLAP;
}
+ return false;
}
static SeqCollection *seq_transform_collection_from_transdata(TransDataContainer *tc)
@@ -607,12 +332,14 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
return;
}
+ TransSeq *ts = tc->custom.type.data;
ListBase *seqbasep = seqbase_active_get(t);
Scene *scene = t->scene;
const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
if (seq_transform_check_overlap(transformed_strips)) {
- SEQ_transform_handle_overlap(scene, seqbasep, transformed_strips, use_sync_markers);
+ SEQ_transform_handle_overlap(
+ scene, seqbasep, transformed_strips, ts->time_dependent_strips, use_sync_markers);
}
SEQ_collection_free(transformed_strips);
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 5a28b8b7318..83b00da0446 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -613,7 +613,7 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
if (info.early_fragment_test_) {
ss << "layout(early_fragment_tests) in;\n";
}
- if (GLEW_VERSION_4_2 || GLEW_ARB_conservative_depth) {
+ if (GLEW_ARB_conservative_depth) {
ss << "layout(" << to_string(info.depth_write_) << ") out float gl_FragDepth;\n";
}
ss << "\n/* Outputs. */\n";
@@ -836,7 +836,7 @@ static char *glsl_patch_default_get()
STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n");
}
- if (!GLEW_VERSION_4_2 && GLEW_ARB_conservative_depth) {
+ if (GLEW_ARB_conservative_depth) {
STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n");
}
if (GPU_shader_image_load_store_support()) {
diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
index 82bb1c57833..1fbddc45964 100644
--- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
@@ -267,6 +267,11 @@ void AbstractHierarchyIterator::export_graph_construct()
{
Scene *scene = DEG_get_evaluated_scene(depsgraph_);
+ /* Add a "null" root node with no children immediately for the case where the top-most node in
+ * the scene is not being exported and a root node otherwise wouldn't get added. */
+ ExportGraph::key_type root_node_id = ObjectIdentifier::for_real_object(nullptr);
+ export_graph_[root_node_id] = ExportChildren();
+
DEG_OBJECT_ITER_BEGIN (depsgraph_,
object,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc
index 5f5c2624414..7de8239b233 100644
--- a/source/blender/io/stl/importer/stl_import_mesh.cc
+++ b/source/blender/io/stl/importer/stl_import_mesh.cc
@@ -21,30 +21,30 @@
namespace blender::io::stl {
-STLMeshHelper::STLMeshHelper(int num_tris, bool use_custom_normals)
- : m_use_custom_normals(use_custom_normals)
+STLMeshHelper::STLMeshHelper(int tris_num, bool use_custom_normals)
+ : use_custom_normals_(use_custom_normals)
{
- m_num_degenerate_tris = 0;
- m_num_duplicate_tris = 0;
- m_tris.reserve(num_tris);
+ degenerate_tris_num_ = 0;
+ duplicate_tris_num_ = 0;
+ tris_.reserve(tris_num);
/* Upper bound (all vertices are unique). */
- m_verts.reserve(num_tris * 3);
+ verts_.reserve(tris_num * 3);
if (use_custom_normals) {
- m_loop_normals.reserve(num_tris * 3);
+ loop_normals_.reserve(tris_num * 3);
}
}
bool STLMeshHelper::add_triangle(const float3 &a, const float3 &b, const float3 &c)
{
- int v1_id = m_verts.index_of_or_add(a);
- int v2_id = m_verts.index_of_or_add(b);
- int v3_id = m_verts.index_of_or_add(c);
+ int v1_id = verts_.index_of_or_add(a);
+ int v2_id = verts_.index_of_or_add(b);
+ int v3_id = verts_.index_of_or_add(c);
if ((v1_id == v2_id) || (v1_id == v3_id) || (v2_id == v3_id)) {
- m_num_degenerate_tris++;
+ degenerate_tris_num_++;
return false;
}
- if (!m_tris.add({v1_id, v2_id, v3_id})) {
- m_num_duplicate_tris++;
+ if (!tris_.add({v1_id, v2_id, v3_id})) {
+ duplicate_tris_num_++;
return false;
}
return true;
@@ -56,18 +56,18 @@ void STLMeshHelper::add_triangle(const float3 &a,
const float3 &custom_normal)
{
if (add_triangle(a, b, c)) {
- m_loop_normals.append_n_times(custom_normal, 3);
+ loop_normals_.append_n_times(custom_normal, 3);
}
}
Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name)
{
- if (m_num_degenerate_tris > 0) {
- std::cout << "STL Importer: " << m_num_degenerate_tris << "degenerate triangles were removed"
+ if (degenerate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << degenerate_tris_num_ << "degenerate triangles were removed"
<< std::endl;
}
- if (m_num_duplicate_tris > 0) {
- std::cout << "STL Importer: " << m_num_duplicate_tris << "duplicate triangles were removed"
+ if (duplicate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << duplicate_tris_num_ << "duplicate triangles were removed"
<< std::endl;
}
@@ -75,36 +75,36 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name)
/* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */
id_us_min(&mesh->id);
- mesh->totvert = m_verts.size();
+ mesh->totvert = verts_.size();
mesh->mvert = static_cast<MVert *>(
CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert));
for (int i = 0; i < mesh->totvert; i++) {
- copy_v3_v3(mesh->mvert[i].co, m_verts[i]);
+ copy_v3_v3(mesh->mvert[i].co, verts_[i]);
}
- mesh->totpoly = m_tris.size();
- mesh->totloop = m_tris.size() * 3;
+ mesh->totpoly = tris_.size();
+ mesh->totloop = tris_.size() * 3;
mesh->mpoly = static_cast<MPoly *>(
CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly));
mesh->mloop = static_cast<MLoop *>(
CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop));
- threading::parallel_for(m_tris.index_range(), 2048, [&](IndexRange tris_range) {
+ threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) {
for (const int i : tris_range) {
mesh->mpoly[i].loopstart = 3 * i;
mesh->mpoly[i].totloop = 3;
- mesh->mloop[3 * i].v = m_tris[i].v1;
- mesh->mloop[3 * i + 1].v = m_tris[i].v2;
- mesh->mloop[3 * i + 2].v = m_tris[i].v3;
+ mesh->mloop[3 * i].v = tris_[i].v1;
+ mesh->mloop[3 * i + 1].v = tris_[i].v2;
+ mesh->mloop[3 * i + 2].v = tris_[i].v3;
}
});
/* NOTE: edges must be calculated first before setting custom normals. */
BKE_mesh_calc_edges(mesh, false, false);
- if (m_use_custom_normals && m_loop_normals.size() == mesh->totloop) {
- BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(m_loop_normals.data()));
+ if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) {
+ BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data()));
mesh->flag |= ME_AUTOSMOOTH;
}
diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh
index a01e5be09a4..f1c0d2126a9 100644
--- a/source/blender/io/stl/importer/stl_import_mesh.hh
+++ b/source/blender/io/stl/importer/stl_import_mesh.hh
@@ -47,15 +47,15 @@ class Triangle {
class STLMeshHelper {
private:
- VectorSet<float3> m_verts;
- VectorSet<Triangle> m_tris;
- Vector<float3> m_loop_normals;
- int m_num_degenerate_tris;
- int m_num_duplicate_tris;
- const bool m_use_custom_normals;
+ VectorSet<float3> verts_;
+ VectorSet<Triangle> tris_;
+ Vector<float3> loop_normals_;
+ int degenerate_tris_num_;
+ int duplicate_tris_num_;
+ const bool use_custom_normals_;
public:
- STLMeshHelper(int num_tris, bool use_custom_normals);
+ STLMeshHelper(int tris_num, bool use_custom_normals);
/* Creates a new triangle from specified vertex locations,
* duplicate vertices and triangles are merged.
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index 0a78cdc714d..a719dff2126 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -45,6 +45,7 @@ struct OBJExportParams {
eEvaluationMode export_eval_mode;
bool export_uv;
bool export_normals;
+ bool export_colors;
bool export_materials;
bool export_triangulated_mesh;
bool export_curves_as_nurbs;
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
index 11d1bafdafe..cb95c561547 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -8,7 +8,9 @@
#include <cstdio>
#include "BKE_blender_version.h"
+#include "BKE_geometry_set.hh"
+#include "BLI_color.hh"
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_path_util.h"
#include "BLI_task.hh"
@@ -241,13 +243,38 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh,
}
void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
- const OBJMesh &obj_mesh_data) const
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const
{
const int tot_count = obj_mesh_data.tot_vertices();
- obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
- float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
- buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
- });
+
+ Mesh *mesh = obj_mesh_data.get_mesh();
+ CustomDataLayer *colors_layer = nullptr;
+ if (write_colors) {
+ colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
+ }
+ if (write_colors && (colors_layer != nullptr)) {
+ MeshComponent component;
+ component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
+
+ BLI_assert(tot_count == attribute.size());
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ ColorGeometry4f linear = attribute.get(i);
+ float srgb[3];
+ linearrgb_to_srgb_v3_v3(srgb, linear);
+ buf.write<eOBJSyntaxElement::vertex_coords_color>(
+ vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]);
+ });
+ }
+ else {
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+ });
+ }
}
void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
index 77da7b44276..97c23484426 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -72,9 +72,11 @@ class OBJWriter : NonMovable, NonCopyable {
*/
void write_mtllib_name(const StringRefNull mtl_filepath) const;
/**
- * Write vertex coordinates for all vertices as "v x y z".
+ * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b".
*/
- void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
+ void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const;
/**
* Write UV vertex coordinates for all vertices as `vt u v`.
* \note UV indices are stored here, but written with polygons later.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
index f0263989bfc..157d7760307 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -30,6 +30,7 @@ enum class eFileType {
enum class eOBJSyntaxElement {
vertex_coords,
+ vertex_coords_color,
uv_vertex_coords,
normal,
poly_element_begin,
@@ -130,6 +131,9 @@ constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key
case eOBJSyntaxElement::vertex_coords: {
return {"v {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>};
}
+ case eOBJSyntaxElement::vertex_coords_color: {
+ return {"v {:.6f} {:.6f} {:.6f} {:.6f} {:.6f} {:.6f}\n", 6, is_type_float<T...>};
+ }
case eOBJSyntaxElement::uv_vertex_coords: {
return {"vt {:.6f} {:.6f}\n", 2, is_type_float<T...>};
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
index 91213ec8152..ee2e6227700 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -241,6 +241,11 @@ class OBJMesh : NonCopyable {
return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
}
+ Mesh *get_mesh() const
+ {
+ return export_mesh_eval_;
+ }
+
private:
/**
* Free the mesh if _the exporter_ created it.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
index b6e636b389d..b0938084efb 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -195,7 +195,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
auto &fh = buffers[i];
obj_writer.write_object_name(fh, obj);
- obj_writer.write_vertex_coords(fh, obj);
+ obj_writer.write_vertex_coords(fh, obj, export_params.export_colors);
if (obj.tot_polygons() > 0) {
if (export_params.export_smooth_groups) {
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
index a627e7261e3..9cfce5c2257 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
@@ -5,12 +5,15 @@
*/
#include "BLI_map.hh"
+#include "BLI_math_color.h"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
#include "obj_import_file_reader.hh"
#include "obj_import_string_utils.hh"
+#include <charconv>
+
namespace blender::io::obj {
using std::string;
@@ -34,6 +37,7 @@ static Geometry *create_geometry(Geometry *const prev_geometry,
g->geom_type_ = new_type;
g->geometry_name_ = name.is_empty() ? "New object" : name;
g->vertex_start_ = global_vertices.vertices.size();
+ g->vertex_color_start_ = global_vertices.vertex_colors.size();
r_offset.set_index_offset(g->vertex_start_);
return g;
};
@@ -71,9 +75,51 @@ static void geom_add_vertex(Geometry *geom,
GlobalVertices &r_global_vertices)
{
float3 vert;
- parse_floats(p, end, 0.0f, vert, 3);
+ p = parse_floats(p, end, 0.0f, vert, 3);
r_global_vertices.vertices.append(vert);
geom->vertex_count_++;
+ /* OBJ extension: "xyzrgb" vertex colors, when the vertex position
+ * is followed by 3 more RGB color components. See
+ * http://paulbourke.net/dataformats/obj/colour.html */
+ if (p < end) {
+ float3 srgb;
+ p = parse_floats(p, end, -1.0f, srgb, 3);
+ if (srgb.x >= 0 && srgb.y >= 0 && srgb.z >= 0) {
+ float3 linear;
+ srgb_to_linearrgb_v3_v3(linear, srgb);
+ r_global_vertices.vertex_colors.append(linear);
+ geom->vertex_color_count_++;
+ }
+ }
+}
+
+static void geom_add_mrgb_colors(Geometry *geom,
+ const char *p,
+ const char *end,
+ GlobalVertices &r_global_vertices)
+{
+ /* MRGB color extension, in the form of
+ * "#MRGB MMRRGGBBMMRRGGBB ..."
+ * http://paulbourke.net/dataformats/obj/colour.html */
+ p = drop_whitespace(p, end);
+ const int mrgb_length = 8;
+ while (p + mrgb_length <= end) {
+ uint32_t value = 0;
+ std::from_chars_result res = std::from_chars(p, p + mrgb_length, value, 16);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ return;
+ }
+ unsigned char srgb[4];
+ srgb[0] = (value >> 16) & 0xFF;
+ srgb[1] = (value >> 8) & 0xFF;
+ srgb[2] = value & 0xFF;
+ srgb[3] = 0xFF;
+ float linear[4];
+ srgb_to_linearrgb_uchar4(linear, srgb);
+ r_global_vertices.vertex_colors.append({linear[0], linear[1], linear[2]});
+ geom->vertex_color_count_++;
+ p += mrgb_length;
+ }
}
static void geom_add_vertex_normal(Geometry *geom,
@@ -149,7 +195,7 @@ static void geom_add_polygon(Geometry *geom,
if (p < end && *p == '/') {
++p;
p = parse_int(p, end, INT32_MAX, corner.vertex_normal_index, false);
- got_normal = corner.uv_vert_index != INT32_MAX;
+ got_normal = corner.vertex_normal_index != INT32_MAX;
}
}
/* Always keep stored indices non-negative and zero-based. */
@@ -172,7 +218,10 @@ static void geom_add_polygon(Geometry *geom,
face_valid = false;
}
}
- if (got_normal) {
+ /* Ignore corner normal index, if the geometry does not have any normals.
+ * Some obj files out there do have face definitions that refer to normal indices,
+ * without any normals being present (T98782). */
+ if (got_normal && geom->has_vertex_normals_) {
corner.vertex_normal_index += corner.vertex_normal_index < 0 ?
global_vertices.vertex_normals.size() :
-1;
@@ -482,6 +531,9 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
else if (parse_keyword(p, end, "mtllib")) {
add_mtl_library(StringRef(p, end).trim());
}
+ else if (parse_keyword(p, end, "#MRGB")) {
+ geom_add_mrgb_colors(curr_geom, p, end, r_global_vertices);
+ }
/* Comments. */
else if (*p == '#') {
/* Nothing to do. */
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
index 854ab96e39f..acc35ad46e1 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
@@ -8,6 +8,7 @@
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -50,6 +51,7 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
create_edges(mesh);
create_uv_verts(mesh);
create_normals(mesh);
+ create_colors(mesh);
create_materials(bmain, materials, created_materials, obj);
if (import_params.validate_meshes || mesh_geometry_.has_invalid_polys_) {
@@ -345,4 +347,26 @@ void MeshFromGeometry::create_normals(Mesh *mesh)
MEM_freeN(loop_normals);
}
+void MeshFromGeometry::create_colors(Mesh *mesh)
+{
+ /* Nothing to do if we don't have vertex colors. */
+ if (mesh_geometry_.vertex_color_count_ < 1) {
+ return;
+ }
+ if (mesh_geometry_.vertex_color_count_ != mesh_geometry_.vertex_count_) {
+ std::cerr << "Mismatching number of vertices (" << mesh_geometry_.vertex_count_
+ << ") and colors (" << mesh_geometry_.vertex_color_count_ << ") on object '"
+ << mesh_geometry_.geometry_name_ << "', ignoring colors." << std::endl;
+ return;
+ }
+
+ CustomDataLayer *color_layer = BKE_id_attribute_new(
+ &mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
+ float4 *colors = (float4 *)color_layer->data;
+ for (int i = 0; i < mesh_geometry_.vertex_color_count_; ++i) {
+ float3 c = global_vertices_.vertex_colors[mesh_geometry_.vertex_color_start_ + i];
+ colors[i] = float4(c.x, c.y, c.z, 1.0f);
+ }
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
index cf4a2aee394..216717f3578 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
@@ -65,6 +65,7 @@ class MeshFromGeometry : NonMovable, NonCopyable {
Map<std::string, Material *> &created_materials,
Object *obj);
void create_normals(Mesh *mesh);
+ void create_colors(Mesh *mesh);
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
index b67ba46af03..69babc26bb0 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
@@ -26,6 +26,7 @@ struct GlobalVertices {
Vector<float3> vertices;
Vector<float2> uv_vertices;
Vector<float3> vertex_normals;
+ Vector<float3> vertex_colors;
};
/**
@@ -102,6 +103,8 @@ struct Geometry {
int vertex_start_ = 0;
int vertex_count_ = 0;
+ int vertex_color_start_ = 0;
+ int vertex_color_count_ = 0;
/** Edges written in the file in addition to (or even without polygon) elements. */
Vector<MEdge> edges_;
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
index b384d934c82..fea74c2fd90 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -436,6 +436,22 @@ TEST_F(obj_exporter_regression_test, cubes_positioned)
_export.params);
}
+/* Disabled until sRGB<->Linear conversion produces close enough results between
+ * SSE2 and non-SSE2.
+TEST_F(obj_exporter_regression_test, cubes_vertex_colors)
+{
+ OBJExportParamsDefault _export;
+ _export.params.export_colors = true;
+ _export.params.export_normals = false;
+ _export.params.export_uv = false;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cubes_vertex_colors.blend",
+ "io_tests/obj/cubes_vertex_colors.obj",
+ "",
+ _export.params);
+}
+*/
+
TEST_F(obj_exporter_regression_test, cubes_with_textures_strip)
{
OBJExportParamsDefault _export;
@@ -494,6 +510,7 @@ TEST_F(obj_exporter_regression_test, all_objects)
_export.params.forward_axis = IO_AXIS_Y;
_export.params.up_axis = IO_AXIS_Z;
_export.params.export_smooth_groups = true;
+ //_export.params.export_colors = true;
compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
"io_tests/obj/all_objects.obj",
"io_tests/obj/all_objects.mtl",
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
index 42f7620999d..7d3b41ed527 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -26,6 +26,7 @@ struct OBJExportParamsDefault {
params.export_selected_objects = false;
params.export_uv = true;
params.export_normals = true;
+ params.export_colors = false;
params.export_materials = true;
params.path_mode = PATH_REFERENCE_AUTO;
params.export_triangulated_mesh = false;
diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
index 6d09f522028..efdd8839615 100644
--- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
@@ -39,6 +39,7 @@ struct Expectation {
float3 vert_first, vert_last;
float3 normal_first;
float2 uv_first;
+ float4 color_first = {-1, -1, -1, -1};
};
class obj_importer_test : public BlendfileLoadingBaseTest {
@@ -98,6 +99,15 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
float2 uv_first = mloopuv ? float2(mloopuv->uv) : float2(0, 0);
EXPECT_V2_NEAR(uv_first, exp.uv_first, 0.0001f);
+ if (exp.color_first.x >= 0) {
+ const float4 *colors = (const float4 *)(CustomData_get_layer(&mesh->vdata,
+ CD_PROP_COLOR));
+ EXPECT_TRUE(colors != nullptr);
+ EXPECT_V4_NEAR(colors[0], exp.color_first, 0.0001f);
+ }
+ else {
+ EXPECT_FALSE(CustomData_has_layer(&mesh->vdata, CD_PROP_COLOR));
+ }
}
if (object->type == OB_CURVES_LEGACY) {
Curve *curve = static_cast<Curve *>(DEG_get_evaluated_object(depsgraph, object)->data);
@@ -434,7 +444,16 @@ TEST_F(obj_importer_test, import_all_objects)
float3(16, 1, -1),
float3(14, 1, 1),
float3(0, 0, 1)},
- {"OBVColCube", OB_MESH, 8, 13, 7, 26, float3(13, 1, -1), float3(11, 1, 1), float3(0, 0, 1)},
+ {"OBVColCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(13, 1, -1),
+ float3(11, 1, 1),
+ float3(0, 0, 1),
+ float2(0, 0)},
{"OBUVCube",
OB_MESH,
8,
@@ -490,4 +509,105 @@ TEST_F(obj_importer_test, import_all_objects)
import_and_check("all_objects.obj", expect, std::size(expect), 7);
}
+/*
+TEST_F(obj_importer_test, import_cubes_vertex_colors)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCubeVertexByte",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1.0f, 1.0f, -1.0f),
+ float3(-1.0f, -1.0f, 1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.846873f, 0.027321f, 0.982251f, 1.0f)},
+ {"OBCubeVertexFloat",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(3.392028f, 1.0f, -1.0f),
+ float3(1.392028f, -1.0f, 1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(49.99558f, 0.027321f, 0.982251f, 1.0f)},
+ {"OBCubeCornerByte",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1.0f, 1.0f, -3.812445f),
+ float3(-1.0f, -1.0f, -1.812445f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.89627f, 0.036889f, 0.47932f, 1.0f)},
+ {"OBCubeCornerFloat",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(3.481967f, 1.0f, -3.812445f),
+ float3(1.481967f, -1.0f, -1.812445f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(1.564582f, 0.039217f, 0.664309f, 1.0f)},
+ {"OBCubeMultiColorAttribs",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-4.725068f, -1.0f, 1.0f),
+ float3(-2.725068f, 1.0f, -1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.270498f, 0.47932f, 0.262251f, 1.0f)},
+ {"OBCubeNoColors",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-4.550208f, -1.0f, -1.918042f),
+ float3(-2.550208f, 1.0f, -3.918042f)},
+ };
+ import_and_check("cubes_vertex_colors.obj", expect, std::size(expect), 0);
+}
+ */
+
+TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb)
+{
+ Expectation expect[] = {{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCubeXYZRGB",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1, 1, -1),
+ float3(-1, -1, 1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.6038f, 0.3185f, 0.1329f, 1.0f)},
+ {"OBCubeMRGB",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(4, 1, -1),
+ float3(2, -1, 1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.8714f, 0.6308f, 0.5271f, 1.0f)}};
+ import_and_check("cubes_vertex_colors_mrgb.obj", expect, std::size(expect), 0);
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index a66badb4a68..2eca84959b8 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -32,6 +32,7 @@ struct MVert;
struct Material;
struct Mesh;
struct SubdivCCG;
+struct SubsurfRuntimeData;
#
#
@@ -123,26 +124,18 @@ typedef struct Mesh_Runtime {
/**
* Settings for lazily evaluating the subdivision on the CPU if needed. These are
- * set in the modifier when GPU subdivision can be performed.
+ * set in the modifier when GPU subdivision can be performed, and owned by the by
+ * the modifier in the object.
*/
- SessionUUID subsurf_session_uuid;
- char subsurf_resolution;
- char subsurf_do_loop_normals;
- char subsurf_apply_render;
- char subsurf_use_optimal_display;
-
- /* Cached from the draw code for stats display. */
- int subsurf_totvert;
- int subsurf_totedge;
- int subsurf_totpoly;
- int subsurf_totloop;
- char _pad2[2];
+ struct SubsurfRuntimeData *subsurf_runtime_data;
+ void *_pad1;
/**
* Caches for lazily computed vertex and polygon normals. These are stored here rather than in
* #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
* const mesh is not thread-safe.
*/
+ char _pad2[6];
char vert_normals_dirty;
char poly_normals_dirty;
float (*vert_normals)[3];
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 6e3ce7e98a8..f148116eba8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -178,13 +178,6 @@ typedef enum {
SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1,
} eSubsurfBoundarySmooth;
-typedef struct SubsurfRuntimeData {
- /* Cached subdivision surface descriptor, with topology and settings. */
- struct Subdiv *subdiv;
- char set_by_draw_code;
- char _pad[7];
-} SubsurfRuntimeData;
-
typedef struct SubsurfModifierData {
ModifierData modifier;
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 4201bab0326..23f447f2469 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -196,16 +196,21 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
/* Cache settings for lazy CPU evaluation. */
-static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
- Mesh *me,
- SubsurfModifierData *smd)
+static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ SubsurfModifierData *smd,
+ SubsurfRuntimeData *runtime_data)
{
SubdivToMeshSettings mesh_settings;
subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
- me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0;
- me->runtime.subsurf_resolution = mesh_settings.resolution;
- me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display;
- me->runtime.subsurf_session_uuid = smd->modifier.session_uuid;
+
+ runtime_data->has_gpu_subdiv = true;
+ runtime_data->resolution = mesh_settings.resolution;
+ runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
+ runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */
+ runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
+
+ mesh->runtime.subsurf_runtime_data = runtime_data;
}
/* Modifier itself. */
@@ -218,13 +223,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return result;
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return result;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
/* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
*/
@@ -237,13 +240,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const bool is_editmode = (mesh->edit_mesh != NULL);
const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
if (BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ctx->object, mesh, smd, required_mode)) {
- subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
+ subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data);
return result;
}
}
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@@ -294,15 +296,11 @@ static void deformMatrices(ModifierData *md,
(void)deform_matrices;
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
index c400760f902..532c3dc81e5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
@@ -65,7 +65,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
float3 reference_normal = poly_normals[i_poly];
float min = FLT_MAX;
- float max = FLT_MIN;
+ float max = -FLT_MAX;
for (const int i_loop : poly_loops.index_range()) {
const float3 vert = mesh->mvert[poly_loops[i_loop].v].co;
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index 93ce6873d3b..31a7399f844 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -46,6 +46,7 @@ bool SEQ_transform_seqbase_shuffle(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene);
bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
+ struct SeqCollection *time_dependent_strips,
struct ListBase *seqbasep,
struct Scene *evil_scene,
struct ListBase *markers,
@@ -54,6 +55,7 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
void SEQ_transform_handle_overlap(struct Scene *scene,
struct ListBase *seqbasep,
struct SeqCollection *transformed_strips,
+ struct SeqCollection *time_dependent_strips,
bool use_sync_markers);
/**
* Check if the selected seq's reference unselected seq's.
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index ebf317eff05..19caf12ff2a 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -13,11 +13,13 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "SEQ_animation.h"
#include "SEQ_channels.h"
+#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
@@ -307,6 +309,7 @@ static int shuffle_seq_time_offset_get(SeqCollection *strips_to_shuffle,
}
bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
+ SeqCollection *time_dependent_strips,
ListBase *seqbasep,
Scene *evil_scene,
ListBase *markers,
@@ -323,6 +326,12 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
seq->flag &= ~SEQ_OVERLAP;
}
+ if (time_dependent_strips != NULL) {
+ SEQ_ITERATOR_FOREACH (seq, time_dependent_strips) {
+ SEQ_offset_animdata(evil_scene, seq, offset);
+ }
+ }
+
if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
TimeMarker *marker;
/* affect selected markers - it's unlikely that we will want to affect all in this way? */
@@ -337,6 +346,296 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
return offset ? false : true;
}
+static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* Query strips positioned after left edge of transformed strips bound-box. */
+static SeqCollection *query_right_side_strips(ListBase *seqbase,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips)
+{
+ int minframe = MAXFRAME;
+ {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(seq));
+ }
+ }
+
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (SEQ_collection_has_strip(seq, time_dependent_strips)) {
+ continue;
+ }
+ if (SEQ_collection_has_strip(seq, transformed_strips)) {
+ continue;
+ }
+
+ if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(seq) >= minframe) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
+ * to overlap of transformed strips. */
+static void seq_transform_handle_expand_to_fit(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ SeqCollection *right_side_strips = query_right_side_strips(
+ seqbasep, transformed_strips, time_dependent_strips);
+
+ /* Temporarily move right side strips beyond timeline boundary. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine += MAXSEQ * 2;
+ }
+
+ /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
+ * strips on left side. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+
+ /* Move temporarily moved strips back to their original place and tag for shuffling. */
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine -= MAXSEQ * 2;
+ }
+ /* Shuffle again to displace strips on right side. Final effect shuffling is done in
+ * SEQ_transform_handle_overlap. */
+ SEQ_transform_seqbase_shuffle_time(
+ right_side_strips, NULL, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(right_side_strips);
+}
+
+static SeqCollection *query_overwrite_targets(ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
+
+ Sequence *seq, *seq_transformed;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ bool does_overlap = false;
+
+ SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
+ /* Effects of transformed strips can be unselected. These must not be included. */
+ if (seq == seq_transformed) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) {
+ does_overlap = true;
+ }
+ }
+
+ if (!does_overlap) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ }
+
+ return collection;
+}
+
+typedef enum eOvelapDescrition {
+ /* No overlap. */
+ STRIP_OVERLAP_NONE,
+ /* Overlapping strip covers overlapped completely. */
+ STRIP_OVERLAP_IS_FULL,
+ /* Overlapping strip is inside overlapped. */
+ STRIP_OVERLAP_IS_INSIDE,
+ /* Partial overlap between 2 strips. */
+ STRIP_OVERLAP_LEFT_SIDE,
+ STRIP_OVERLAP_RIGHT_SIDE,
+} eOvelapDescrition;
+
+static eOvelapDescrition overlap_description_get(const Sequence *transformed,
+ const Sequence *target)
+{
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(transformed) >= SEQ_time_right_handle_frame_get(target)) {
+ return STRIP_OVERLAP_IS_FULL;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) > SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(transformed) < SEQ_time_right_handle_frame_get(target)) {
+ return STRIP_OVERLAP_IS_INSIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_left_handle_frame_get(target) &&
+ SEQ_time_left_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
+ return STRIP_OVERLAP_LEFT_SIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(transformed) <= SEQ_time_right_handle_frame_get(target) &&
+ SEQ_time_right_handle_frame_get(target) <= SEQ_time_right_handle_frame_get(transformed)) {
+ return STRIP_OVERLAP_RIGHT_SIDE;
+ }
+ return STRIP_OVERLAP_NONE;
+}
+
+/* Split strip in 3 parts, remove middle part and fit transformed inside. */
+static void seq_transform_handle_overwrite_split(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target)
+{
+ /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
+ * NULL here. */
+ Main *bmain = NULL;
+
+ Sequence *split_strip = SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ target,
+ SEQ_time_left_handle_frame_get(transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ split_strip,
+ SEQ_time_right_handle_frame_get(transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+}
+
+/* Trim strips by adjusting handle position.
+ * This is bit more complicated in case overlap happens on effect. */
+static void seq_transform_handle_overwrite_trim(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target,
+ const eOvelapDescrition overlap)
+{
+ SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain);
+
+ /* Expand collection by adding all target's children, effects and their children. */
+ if ((target->type & SEQ_TYPE_EFFECT) != 0) {
+ SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain);
+ }
+
+ /* Trim all non effects, that have influence on effect length which is overlapping. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, targets) {
+ if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
+ continue;
+ }
+ if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
+ SEQ_time_left_handle_frame_set(scene, seq, SEQ_time_right_handle_frame_get(transformed));
+ }
+ else {
+ BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
+ SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(transformed));
+ }
+ }
+ SEQ_collection_free(targets);
+}
+
+static void seq_transform_handle_overwrite(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips);
+ SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+
+ Sequence *target;
+ Sequence *transformed;
+ SEQ_ITERATOR_FOREACH (target, targets) {
+ SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
+ if (transformed->machine != target->machine) {
+ continue;
+ }
+
+ const eOvelapDescrition overlap = overlap_description_get(transformed, target);
+
+ if (overlap == STRIP_OVERLAP_IS_FULL) {
+ SEQ_collection_append_strip(target, strips_to_delete);
+ }
+ else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
+ seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
+ }
+ else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
+ seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
+ }
+ }
+ }
+
+ SEQ_collection_free(targets);
+
+ /* Remove covered strips. This must be done in separate loop, because `SEQ_edit_strip_split()`
+ * also uses `SEQ_edit_remove_flagged_sequences()`. See T91096. */
+ if (SEQ_collection_len(strips_to_delete) > 0) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips_to_delete) {
+ SEQ_edit_flag_for_removal(scene, seqbasep, seq);
+ }
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+ }
+ SEQ_collection_free(strips_to_delete);
+}
+
+static void seq_transform_handle_overlap_shuffle(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ /* Shuffle non strips with no effects attached. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+}
+
+void SEQ_transform_handle_overlap(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
+
+ switch (overlap_mode) {
+ case SEQ_OVERLAP_EXPAND:
+ seq_transform_handle_expand_to_fit(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ case SEQ_OVERLAP_OVERWRITE:
+ seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
+ break;
+ case SEQ_OVERLAP_SHUFFLE:
+ seq_transform_handle_overlap_shuffle(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ }
+
+ /* If any effects still overlap, we need to move them up.
+ * In some cases other strips can be overlapping still, see T90646. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if (SEQ_transform_test_overlap(seqbasep, seq)) {
+ SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ }
+ seq->flag &= ~SEQ_OVERLAP;
+ }
+}
+
void SEQ_transform_offset_after_frame(Scene *scene,
ListBase *seqbase,
const int delta,
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index ac06ababfd4..60cded3b869 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -738,6 +738,7 @@ void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct Pointe
wmOperator *WM_operator_last_redo(const struct bContext *C);
/**
* Use for drag & drop a path or name with operators invoke() function.
+ * Returns null if no operator property is set to identify the file or ID to use.
*/
ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, short idcode);
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index c2a63c9db7a..63a7fb5ddaa 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -1153,9 +1153,17 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
if (wm_software_cursor_needed()) {
struct GrabState grab_state;
- if (wm_software_cursor_needed_for_window(win, &grab_state) &&
- wm_software_cursor_motion_test(win)) {
- return true;
+ if (wm_software_cursor_needed_for_window(win, &grab_state)) {
+ if (wm_software_cursor_motion_test(win)) {
+ return true;
+ }
+ }
+ else {
+ /* Detect the edge case when the previous draw used the software cursor but this one doesn't,
+ * it's important to redraw otherwise the software cursor will remain displayed. */
+ if (g_software_cursor.winid != -1) {
+ return true;
+ }
}
}
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 531da3cf2e8..0817b10f86e 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -270,7 +270,10 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
- else if (STRPREFIX(opname, "CURVES_SCULPT_OT")) {
+ else if (STRPREFIX(opname, "CURVES_OT")) {
+ km = WM_keymap_find_all(wm, "Curves", 0, 0);
+ }
+ else if (STRPREFIX(opname, "SCULPT_CURVES_OT")) {
km = WM_keymap_find_all(wm, "Sculpt Curves", 0, 0);
}
else if (STRPREFIX(opname, "MBALL_OT")) {
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 7b768bd8c70..9f21e952850 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1308,6 +1308,10 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i
return id;
}
+ if (!WM_operator_properties_id_lookup_is_set(op->ptr)) {
+ return NULL;
+ }
+
/* Lookup an already existing ID. */
id = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, idcode);
diff --git a/tests/python/modules/render_report.py b/tests/python/modules/render_report.py
index cae81af3144..15441918800 100755
--- a/tests/python/modules/render_report.py
+++ b/tests/python/modules/render_report.py
@@ -253,8 +253,11 @@ class Report:
failed = len(failed_tests) > 0
if failed:
message = """<div class="alert alert-danger" role="alert">"""
- message += """Run this command to update reference images for failed tests, or create images for new tests:<br>"""
- message += """<tt>BLENDER_TEST_UPDATE=1 ctest -R %s</tt>""" % self.title.lower()
+ message += """<p>Run this command to regenerate reference (ground truth) images:</p>"""
+ message += """<p><tt>BLENDER_TEST_UPDATE=1 ctest -R %s</tt></p>""" % self.title.lower()
+ message += """<p>This then happens for new and failing tests; reference images of """ \
+ """passing test cases will not be updated. Be sure to commit the new reference """ \
+ """images to the SVN repository afterwards.</p>"""
message += """</div>"""
else:
message = ""
@@ -294,6 +297,7 @@ class Report:
background-position:0 0, 25px 0, 25px -25px, 0px 25px;
}}
table td:first-child {{ width: 256px; }}
+ p {{ margin-bottom: 0.5rem; }}
</style>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>