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:
authorHimanshi Kalra <himanshikalra98@gmail.com>2020-12-17 15:06:26 +0300
committerHimanshi Kalra <himanshikalra98@gmail.com>2020-12-17 15:06:26 +0300
commit167eace0e73bef77cf362af04f1f0dd47c492a92 (patch)
tree715217755512456fab8dfa8e38f63d5065a1ccc1
parentf066bf923c234f52a6159d51f4978bf1072edaf1 (diff)
parentcf2ebaf27c78b3f8f79d9d014ca2261228f87e70 (diff)
Merge branch 'master' into soc-2020-testing-frameworks
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.cpp5
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp69
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h14
m---------release/datafiles/locale0
m---------release/scripts/addons0
-rw-r--r--release/scripts/modules/bl_keymap_utils/io.py11
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py4
-rw-r--r--release/scripts/startup/bl_operators/assets.py1
-rw-r--r--release/scripts/startup/bl_operators/geometry_nodes.py3
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py5
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py52
-rw-r--r--release/scripts/startup/bl_ui/space_image.py4
-rw-r--r--release/scripts/startup/bl_ui/space_node.py1
-rw-r--r--release/scripts/startup/bl_ui/space_properties.py6
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py135
-rw-r--r--release/scripts/startup/bl_ui/space_time.py1
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py4
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py19
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py1
-rw-r--r--release/scripts/startup/nodeitems_builtins.py3
-rw-r--r--release/steam/README.md70
-rw-r--r--release/steam/blender_app_build.vdf.template17
-rw-r--r--release/steam/create_steam_builds.py397
-rw-r--r--release/steam/depot_build_linux.vdf.template31
-rw-r--r--release/steam/depot_build_macos.vdf.template30
-rw-r--r--release/steam/depot_build_win.vdf.template31
-rw-r--r--source/blender/blenfont/intern/blf_dir.c11
-rw-r--r--source/blender/blenkernel/BKE_action.h4
-rw-r--r--source/blender/blenkernel/BKE_anim_visualization.h4
-rw-r--r--source/blender/blenkernel/BKE_animsys.h2
-rw-r--r--source/blender/blenkernel/BKE_asset.h2
-rw-r--r--source/blender/blenkernel/BKE_attribute.h1
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh4
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_collision.h2
-rw-r--r--source/blender/blenkernel/BKE_constraint.h8
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h5
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.h4
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh4
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h4
-rw-r--r--source/blender/blenkernel/BKE_gpencil_curve.h4
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h3
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h6
-rw-r--r--source/blender/blenkernel/BKE_ipo.h1
-rw-r--r--source/blender/blenkernel/BKE_lattice.h1
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h1
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h1
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh_fair.h56
-rw-r--r--source/blender/blenkernel/BKE_modifier.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/BKE_paint.h7
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h1
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h6
-rw-r--r--source/blender/blenkernel/BKE_screen.h1
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h6
-rw-r--r--source/blender/blenkernel/BKE_speaker.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt3
-rw-r--r--source/blender/blenkernel/intern/appdir.c12
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc21
-rw-r--r--source/blender/blenkernel/intern/brush.c9
-rw-r--r--source/blender/blenkernel/intern/customdata.c16
-rw-r--r--source/blender/blenkernel/intern/icons.cc72
-rw-r--r--source/blender/blenkernel/intern/image_gpu.c2
-rw-r--r--source/blender/blenkernel/intern/layer.c2
-rw-r--r--source/blender/blenkernel/intern/lib_override.c38
-rw-r--r--source/blender/blenkernel/intern/mesh_fair.cc505
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.h2
-rw-r--r--source/blender/blenkernel/intern/node.c3
-rw-r--r--source/blender/blenkernel/intern/scene.c12
-rw-r--r--source/blender/blenlib/BLI_array.hh4
-rw-r--r--source/blender/blenlib/BLI_index_range.hh45
-rw-r--r--source/blender/blenlib/BLI_inplace_priority_queue.hh304
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h1
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh19
-rw-r--r--source/blender/blenlib/BLI_span.hh129
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh126
-rw-r--r--source/blender/blenlib/BLI_threads.h1
-rw-r--r--source/blender/blenlib/BLI_vector.hh4
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c19
-rw-r--r--source/blender/blenlib/tests/BLI_index_range_test.cc7
-rw-r--r--source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc113
-rw-r--r--source/blender/blenlib/tests/BLI_memory_utils_test.cc11
-rw-r--r--source/blender/blenlib/tests/BLI_span_test.cc15
-rw-r--r--source/blender/blenlib/tests/BLI_string_ref_test.cc8
-rw-r--r--source/blender/blenloader/BLO_read_write.h1
-rw-r--r--source/blender/blenloader/intern/readfile.h3
-rw-r--r--source/blender/blenloader/intern/versioning_290.c207
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c11
-rw-r--r--source/blender/blenloader/intern/writefile.c5
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h1
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h4
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h3
-rw-r--r--source/blender/draw/engines/image/image_private.h2
-rw-r--r--source/blender/draw/intern/DRW_render.h1
-rw-r--r--source/blender/draw/intern/draw_common.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c9
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c69
-rw-r--r--source/blender/editors/include/ED_armature.h1
-rw-r--r--source/blender/editors/include/ED_fileselect.h4
-rw-r--r--source/blender/editors/include/ED_gpencil.h1
-rw-r--r--source/blender/editors/include/ED_image.h2
-rw-r--r--source/blender/editors/include/ED_object.h1
-rw-r--r--source/blender/editors/include/ED_screen.h1
-rw-r--r--source/blender/editors/include/ED_transform.h2
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h1
-rw-r--r--source/blender/editors/include/ED_util.h1
-rw-r--r--source/blender/editors/include/ED_util_imbuf.h1
-rw-r--r--source/blender/editors/include/ED_uvedit.h1
-rw-r--r--source/blender/editors/include/ED_view3d.h5
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/interface/interface_icons.c5
-rw-r--r--source/blender/editors/object/object_relations.c11
-rw-r--r--source/blender/editors/object/object_vgroup.c3
-rw-r--r--source/blender/editors/render/render_internal.c18
-rw-r--r--source/blender/editors/screen/screen_edit.c186
-rw-r--r--source/blender/editors/screen/screen_ops.c1
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h1
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c195
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c37
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c91
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h9
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c5
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h1
-rw-r--r--source/blender/editors/space_file/filelist.c45
-rw-r--r--source/blender/editors/space_file/filelist.h2
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_file/space_file.c17
-rw-r--r--source/blender/editors/space_node/drawnode.c22
-rw-r--r--source/blender/editors/space_outliner/outliner_context.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c13
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_nla.hh1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c29
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c287
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c287
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c4
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c6
-rw-r--r--source/blender/editors/transform/transform.h2
-rw-r--r--source/blender/editors/transform/transform_convert.h3
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c3
-rw-r--r--source/blender/editors/transform/transform_snap.h2
-rw-r--r--source/blender/editors/util/ed_util.c41
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c15
-rw-r--r--source/blender/gpu/GPU_shader.h2
-rw-r--r--source/blender/gpu/GPU_texture.h8
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h3
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h2
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c6
-rw-r--r--source/blender/imbuf/IMB_imbuf.h2
-rw-r--r--source/blender/imbuf/intern/anim_movie.c10
-rw-r--r--source/blender/io/alembic/exporter/abc_hierarchy_iterator.h1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_abstract.h1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_hair.h3
-rw-r--r--source/blender/io/alembic/intern/abc_reader_archive.h1
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h2
-rw-r--r--source/blender/io/usd/intern/usd_exporter_context.h1
-rw-r--r--source/blender/io/usd/intern/usd_hierarchy_iterator.h1
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.h1
-rw-r--r--source/blender/io/usd/usd.h1
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h1
-rw-r--r--source/blender/makesdna/DNA_brush_types.h2
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h1
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h2
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h11
-rw-r--r--source/blender/makesdna/DNA_object_types.h4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h15
-rw-r--r--source/blender/makesdna/DNA_space_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c1
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c6
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c44
-rw-r--r--source/blender/makesrna/intern/rna_scene.c38
-rw-r--r--source/blender/makesrna/intern/rna_space.c25
-rw-r--r--source/blender/modifiers/MOD_nodes.h2
-rw-r--r--source/blender/nodes/CMakeLists.txt4
-rw-r--r--source/blender/nodes/NOD_geometry.h3
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh2
-rw-r--r--source/blender/nodes/NOD_static_types.h5
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc107
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc)34
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc178
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc281
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc3
-rw-r--r--source/blender/nodes/intern/node_tree_multi_function.cc4
-rw-r--r--source/blender/python/BPY_extern.h1
-rw-r--r--source/blender/render/RE_pipeline.h2
-rw-r--r--source/blender/render/intern/engine.c4
-rw-r--r--source/blender/render/intern/pipeline.c6
-rw-r--r--source/blender/render/intern/render_result.c47
-rw-r--r--source/blender/render/intern/render_result.h1
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h57
-rw-r--r--source/blender/sequencer/intern/effects.h2
-rw-r--r--source/blender/sequencer/intern/image_cache.h2
-rw-r--r--source/blender/sequencer/intern/multiview.h7
-rw-r--r--source/blender/sequencer/intern/prefetch.h4
-rw-r--r--source/blender/sequencer/intern/proxy.h2
-rw-r--r--source/blender/sequencer/intern/render.c35
-rw-r--r--source/blender/sequencer/intern/render.h1
-rw-r--r--source/blender/sequencer/intern/sequencer.c47
-rw-r--r--source/blender/sequencer/intern/strip_add.c15
-rw-r--r--source/blender/sequencer/intern/strip_edit.c35
-rw-r--r--source/blender/sequencer/intern/strip_time.c82
-rw-r--r--source/blender/sequencer/intern/strip_time.h12
-rw-r--r--source/blender/sequencer/intern/strip_transform.c30
-rw-r--r--source/blender/sequencer/intern/utils.c34
-rw-r--r--source/blender/sequencer/intern/utils.h1
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c7
-rw-r--r--source/blender/windowmanager/wm.h1
231 files changed, 4548 insertions, 1041 deletions
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
index fdfde13b915..86f3a0a31fb 100644
--- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
@@ -142,7 +142,8 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDi
}
static string path = "";
- string command = string("xdg-user-dir ") + type_str;
+ /* Pipe stderr to /dev/null to avoid error prints. We will fail gracefully still. */
+ string command = string("xdg-user-dir ") + type_str + " 2> /dev/null";
FILE *fstream = popen(command.c_str(), "r");
if (fstream == NULL) {
@@ -163,7 +164,7 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDi
}
path = path_stream.str();
- return (const GHOST_TUns8 *)path.c_str();
+ return path[0] ? (const GHOST_TUns8 *)path.c_str() : NULL;
}
const GHOST_TUns8 *GHOST_SystemPathsUnix::getBinaryDir() const
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index d2aebab026f..2bf1d0c2d35 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -1614,7 +1614,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
break;
}
case WT_PACKET:
- window->updatePendingWintabEvents();
+ window->updateWintabEventsSyncTime();
break;
////////////////////////////////////////////////////////////////////////
// Pointer events, processed
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index af02663985d..a4cbf66b22d 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -1292,7 +1292,7 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
- updatePendingWintabEvents();
+ updateWintabEvents();
auto &pendingEvents = m_wintab.pendingEvents;
size_t pendingEventSize = pendingEvents.size();
@@ -1388,6 +1388,44 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
return GHOST_kSuccess;
}
+void GHOST_WindowWin32::updateWintabEvents()
+{
+ readWintabEvents();
+ // When a Wintab device is used to leave window focus, some of it's packets are periodically not
+ // queued in time to be flushed. Reading packets needs to occur before expiring packets to clear
+ // these from the queue.
+ expireWintabEvents();
+}
+
+void GHOST_WindowWin32::updateWintabEventsSyncTime()
+{
+ readWintabEvents();
+
+ if (!m_wintab.pendingEvents.empty()) {
+ auto lastEvent = m_wintab.pendingEvents.back();
+ m_wintab.sysTimeOffset = ::GetTickCount() - lastEvent.pkTime;
+ }
+
+ expireWintabEvents();
+}
+
+void GHOST_WindowWin32::readWintabEvents()
+{
+ if (!(m_wintab.packetsGet && m_wintab.context)) {
+ return;
+ }
+
+ auto &pendingEvents = m_wintab.pendingEvents;
+
+ /* Get new packets. */
+ const int numPackets = m_wintab.packetsGet(
+ m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
+
+ for (int i = 0; i < numPackets; i++) {
+ pendingEvents.push(m_wintab.pkts[i]);
+ }
+}
+
/* Wintab (per documentation but may vary with implementation) does not update when its event
* buffer is full. This is an issue because we need some synchronization point between Wintab
* events and Win32 events, so we can't drain and process the queue immediately. We need to
@@ -1396,17 +1434,12 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
* mode from the Wintab API alone. There is no guaranteed ordering between Wintab and Win32 mouse
* events and no documented time stamp shared between the two, so we synchronize on mouse button
* events. */
-void GHOST_WindowWin32::updatePendingWintabEvents()
+void GHOST_WindowWin32::expireWintabEvents()
{
- if (!(m_wintab.packetsGet && m_wintab.context)) {
- return;
- }
-
auto &pendingEvents = m_wintab.pendingEvents;
- /* Clear outdated events from queue. */
- DWORD currTime = ::GetTickCount();
- DWORD millisTimeout = 500;
+ DWORD currTime = ::GetTickCount() - m_wintab.sysTimeOffset;
+ DWORD millisTimeout = 300;
while (!pendingEvents.empty()) {
DWORD pkTime = pendingEvents.front().pkTime;
@@ -1417,24 +1450,6 @@ void GHOST_WindowWin32::updatePendingWintabEvents()
break;
}
}
-
- /* Get new packets. */
- const int numPackets = m_wintab.packetsGet(
- m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
-
- int i = 0;
- /* Don't queue outdated packets, such events can include packets that occurred before the current
- * window lost and regained focus. */
- for (; i < numPackets; i++) {
- DWORD pkTime = m_wintab.pkts[i].pkTime;
-
- if (currTime < pkTime + millisTimeout) {
- break;
- }
- }
- for (; i < numPackets; i++) {
- pendingEvents.push(m_wintab.pkts[i]);
- }
}
GHOST_TUns16 GHOST_WindowWin32::getDPIHint()
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index a761d7d84dc..829bbdea051 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -486,9 +486,14 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TSuccess getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo);
/**
- * Updates stored pending Wintab events.
+ * Updates pending Wintab events and syncs Wintab time with OS time.
*/
- void updatePendingWintabEvents();
+ void updateWintabEventsSyncTime();
+
+ /**
+ * Updates pending Wintab events.
+ */
+ void updateWintabEvents();
GHOST_TSuccess beginFullScreen() const
{
@@ -629,6 +634,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TUns8 numSysButtons = 0;
/** Cursors currently in contact mapped to system buttons */
DWORD sysButtonsPressed = 0;
+ DWORD sysTimeOffset = 0;
LONG maxPressure = 0;
LONG maxAzimuth = 0, maxAltitude = 0;
/** Reusable buffer to read in Wintab Packets. */
@@ -642,6 +648,10 @@ class GHOST_WindowWin32 : public GHOST_Window {
*/
void initializeWintab();
+ void readWintabEvents();
+
+ void expireWintabEvents();
+
/**
* Convert Wintab system mapped (mouse) buttons into Ghost button mask.
* \param cursor: The Wintab cursor associated to the button.
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 9e40c01dffd3f720b23b906d20df8e999d34a4a
+Subproject 877a343fed9613d8e02e7fe7181d3bbb628506f
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 1a3f127714e8da9f0af12d9a174dae9793ae63c
+Subproject a3fa40ec0ba525bc96cbfad49f854a0230b0524
diff --git a/release/scripts/modules/bl_keymap_utils/io.py b/release/scripts/modules/bl_keymap_utils/io.py
index 091cdbc2642..645a145f994 100644
--- a/release/scripts/modules/bl_keymap_utils/io.py
+++ b/release/scripts/modules/bl_keymap_utils/io.py
@@ -222,12 +222,21 @@ def keyconfig_export_as_data(wm, kc, filepath, *, all_keymaps=False):
fw("]\n")
fw("\n\n")
fw("if __name__ == \"__main__\":\n")
+
+ # We could remove this in the future, as loading new key-maps in older Blender versions
+ # makes less and less sense as Blender changes.
+ fw(" # Only add keywords that are supported.\n")
+ fw(" from bpy.app import version as blender_version\n")
+ fw(" keywords = {}\n")
+ fw(" if blender_version >= (2, 92, 0):\n")
+ fw(" keywords[\"keyconfig_version\"] = keyconfig_version\n")
+
fw(" import os\n")
fw(" from bl_keymap_utils.io import keyconfig_import_from_data\n")
fw(" keyconfig_import_from_data(\n")
fw(" os.path.splitext(os.path.basename(__file__))[0],\n")
fw(" keyconfig_data,\n")
- fw(" keyconfig_version=keyconfig_version,\n")
+ fw(" **keywords,\n")
fw(" )\n")
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 5a5957b8bf1..d3990851e2c 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -1217,7 +1217,7 @@ def km_view3d(params):
("transform.mirror", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
("wm.context_toggle", {"type": 'TAB', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.use_snap')]}),
- op_panel("VIEW3D_PT_snapping", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, [("keep_open", False)]),
+ op_panel("VIEW3D_PT_snapping", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, [("keep_open", True)]),
("object.transform_axis_target", {"type": 'T', "value": 'PRESS', "shift": True}, None),
("transform.skin_resize", {"type": 'A', "value": 'PRESS', "ctrl": True}, None),
])
@@ -2501,6 +2501,8 @@ def km_sequencer(params):
("sequencer.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("sequencer.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("sequencer.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
+ ("sequencer.paste", {"type": 'V', "value": 'PRESS', "ctrl": True, "shift": True},
+ {"properties": [("keep_offset", True)]}),
("sequencer.images_separate", {"type": 'Y', "value": 'PRESS'}, None),
("sequencer.meta_toggle", {"type": 'TAB', "value": 'PRESS'}, None),
("sequencer.meta_make", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
diff --git a/release/scripts/startup/bl_operators/assets.py b/release/scripts/startup/bl_operators/assets.py
index c317df78aa5..317555280e5 100644
--- a/release/scripts/startup/bl_operators/assets.py
+++ b/release/scripts/startup/bl_operators/assets.py
@@ -22,6 +22,7 @@ from bpy_extras.asset_utils import (
SpaceAssetInfo,
)
+
class ASSET_OT_tag_add(bpy.types.Operator):
"""Add a new keyword tag to the active asset"""
diff --git a/release/scripts/startup/bl_operators/geometry_nodes.py b/release/scripts/startup/bl_operators/geometry_nodes.py
index 7d7e3793dba..b94104d10a9 100644
--- a/release/scripts/startup/bl_operators/geometry_nodes.py
+++ b/release/scripts/startup/bl_operators/geometry_nodes.py
@@ -18,6 +18,7 @@
import bpy
+
def geometry_node_group_empty_new(context):
group = bpy.data.node_groups.new("Geometry Nodes", 'GeometryNodeTree')
group.inputs.new('NodeSocketGeometry', "Geometry")
@@ -33,6 +34,7 @@ def geometry_node_group_empty_new(context):
return group
+
def geometry_modifier_poll(context) -> bool:
ob = context.object
@@ -42,6 +44,7 @@ def geometry_modifier_poll(context) -> bool:
return True
+
class NewGeometryNodesModifier(bpy.types.Operator):
"""Create a new modifier with a new geometry node group"""
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 8c275da28ac..0600536cb66 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -573,6 +573,7 @@ class QuickLiquid(Operator):
return {'FINISHED'}
+
classes = (
QuickExplode,
QuickFur,
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 8201ce080b1..c663a736441 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -893,6 +893,7 @@ class GreasePencilLayerDisplayPanel:
row = layout.row(align=True)
row.prop(gpl, "use_solo_mode", text="Show Only on Keyframed")
+
class GreasePencilFlipTintColors(Operator):
bl_label = "Flip Colors"
bl_idname = "gpencil.tint_flip"
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 7e9e15c30da..5d241e8e216 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -550,7 +550,6 @@ def brush_settings(layout, context, brush, popover=False):
if context.preferences.experimental.use_sculpt_tools_tilt and capabilities.has_tilt:
layout.prop(brush, "tilt_strength_factor", slider=True)
-
row = layout.row(align=True)
row.prop(brush, "hardness", slider=True)
row.prop(brush, "invert_hardness_pressure", text="")
@@ -765,6 +764,10 @@ def brush_settings(layout, context, brush, popover=False):
col.prop(brush, "surface_smooth_current_vertex")
col.prop(brush, "surface_smooth_iterations")
+ elif sculpt_tool == 'DISPLACEMENT_SMEAR':
+ col = layout.column()
+ col.prop(brush, "smear_deform_type")
+
elif sculpt_tool == 'MASK':
layout.row().prop(brush, "mask_tool", expand=True)
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 527a5bc623e..98b155d8a21 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -267,7 +267,11 @@ class FILEBROWSER_PT_bookmarks_system(Panel):
@classmethod
def poll(cls, context):
- return not context.preferences.filepaths.hide_system_bookmarks and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
+ return (
+ not context.preferences.filepaths.hide_system_bookmarks and
+ panel_poll_is_upper_region(context.region) and
+ not panel_poll_is_asset_browsing(context)
+ )
def draw(self, context):
layout = self.layout
@@ -301,7 +305,10 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel):
@classmethod
def poll(cls, context):
- return panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
+ return (
+ panel_poll_is_upper_region(context.region) and
+ not panel_poll_is_asset_browsing(context)
+ )
def draw(self, context):
layout = self.layout
@@ -338,7 +345,11 @@ class FILEBROWSER_PT_bookmarks_recents(Panel):
@classmethod
def poll(cls, context):
- return not context.preferences.filepaths.hide_recent_locations and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
+ return (
+ not context.preferences.filepaths.hide_recent_locations and
+ panel_poll_is_upper_region(context.region) and
+ not panel_poll_is_asset_browsing(context)
+ )
def draw(self, context):
layout = self.layout
@@ -362,7 +373,11 @@ class FILEBROWSER_PT_advanced_filter(Panel):
@classmethod
def poll(cls, context):
# only useful in append/link (library) context currently...
- return context.space_data.params.use_library_browsing and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
+ return (
+ context.space_data.params.use_library_browsing and
+ panel_poll_is_upper_region(context.region) and
+ not panel_poll_is_asset_browsing(context)
+ )
def draw(self, context):
layout = self.layout
@@ -573,23 +588,33 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
active_file = context.active_file
active_asset = asset_utils.SpaceAssetInfo.get_active_asset(context)
- layout.use_property_split = True
-
if not active_file or not active_asset:
- layout.label(text="No asset selected.")
+ layout.label(text="No asset selected.", icon='INFO')
return
- box = layout.box()
+ # If the active file is an ID, use its name directly so renaming is possible from right here.
+ layout.prop(context.id if context.id is not None else active_file, "name", text="")
+
+
+class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel):
+ bl_label = "Preview"
+
+ def draw(self, context):
+ layout = self.layout
+ active_file = context.active_file
+
+ row = layout.row()
+ box = row.box()
box.template_icon(icon_value=active_file.preview_icon_id, scale=5.0)
if bpy.ops.ed.lib_id_load_custom_preview.poll():
- box.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="Load Custom")
- layout.prop(active_file, "name")
+ col = row.column(align=True)
+ col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="")
+ col.separator()
+ col.operator("ed.lib_id_generate_preview", icon='FILE_REFRESH', text="")
-class ASSETBROWSER_PT_metadata_details(asset_utils.AssetBrowserPanel, Panel):
- bl_region_type = 'TOOL_PROPS'
+class ASSETBROWSER_PT_metadata_details(asset_utils.AssetMetaDataPanel, Panel):
bl_label = "Details"
- bl_parent_id = "ASSETBROWSER_PT_metadata"
def draw(self, context):
layout = self.layout
@@ -647,6 +672,7 @@ classes = (
FILEBROWSER_MT_context_menu,
ASSETBROWSER_PT_navigation_bar,
ASSETBROWSER_PT_metadata,
+ ASSETBROWSER_PT_metadata_preview,
ASSETBROWSER_PT_metadata_details,
ASSETBROWSER_PT_metadata_tags,
ASSETBROWSER_UL_metadata_tags,
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index f4e88b70281..342b72acb8c 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -1465,7 +1465,7 @@ class IMAGE_PT_overlay(Panel):
bl_ui_units_x = 13
def draw(self, context):
- pass
+ pass
class IMAGE_PT_overlay_uv_edit(Panel):
@@ -1496,7 +1496,6 @@ class IMAGE_PT_overlay_uv_edit(Panel):
subrow.prop(uvedit, "display_stretch_type", text="")
-
class IMAGE_PT_overlay_uv_edit_geometry(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'
@@ -1529,7 +1528,6 @@ class IMAGE_PT_overlay_uv_edit_geometry(Panel):
row.prop(uvedit, "show_faces", text="Faces")
-
class IMAGE_PT_overlay_texture_paint(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 1c4d1919f43..e6af83b61f4 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -168,7 +168,6 @@ class NODE_HT_header(Header):
else:
row.template_ID(snode, "node_tree", new="node.new_geometry_nodes_modifier")
-
else:
# Custom node tree is edited as independent ID block
NODE_MT_editor_menus.draw_collapsible(context, layout)
diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py
index 0f64ab63d6b..765cab1ace2 100644
--- a/release/scripts/startup/bl_ui/space_properties.py
+++ b/release/scripts/startup/bl_ui/space_properties.py
@@ -61,8 +61,10 @@ class PROPERTIES_PT_navigation_bar(Panel):
layout.scale_x = 1.4
layout.scale_y = 1.4
if view.search_filter:
- layout.prop_tabs_enum(view, "context", data_highlight=view,
- property_highlight="tab_search_results", icon_only=True)
+ layout.prop_tabs_enum(
+ view, "context", data_highlight=view,
+ property_highlight="tab_search_results", icon_only=True,
+ )
else:
layout.prop_tabs_enum(view, "context", icon_only=True)
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 3f92fce81f6..e79b5d3e2c8 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -129,6 +129,8 @@ class SEQUENCER_HT_header(Header):
layout = self.layout
st = context.space_data
+ scene = context.scene
+ sequencer_tool_settings = context.tool_settings.sequencer_tool_settings
show_region_tool_header = st.show_region_tool_header
@@ -139,12 +141,17 @@ class SEQUENCER_HT_header(Header):
SEQUENCER_MT_editor_menus.draw_collapsible(context, layout)
- if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
-
+ if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
+ layout.separator_spacer()
+ row = layout.row(align=True)
+ row.prop(sequencer_tool_settings, "fit_method", text="")
layout.separator_spacer()
- layout.prop(st, "display_mode", text="", icon_only=True)
+ if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
+ if st.view_type == 'PREVIEW':
+ layout.separator_spacer()
+ layout.prop(st, "display_mode", text="", icon_only=True)
layout.prop(st, "preview_channels", text="", icon_only=True)
gpd = context.gpencil_data
@@ -157,6 +164,12 @@ class SEQUENCER_HT_header(Header):
if tool_settings.use_proportional_edit:
row.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
+ row = layout.row(align=True)
+ row.prop(st, "show_strip_overlay", text="", icon='OVERLAY')
+ sub = row.row(align=True)
+ sub.popover(panel="SEQUENCER_PT_overlay", text="")
+ sub.active = st.show_strip_overlay
+
class SEQUENCER_MT_editor_menus(Menu):
bl_idname = "SEQUENCER_MT_editor_menus"
@@ -176,6 +189,80 @@ class SEQUENCER_MT_editor_menus(Menu):
layout.menu("SEQUENCER_MT_strip")
+class SEQUENCER_PT_overlay(Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_label = "Overlays"
+ bl_ui_units_x = 7
+
+ def draw(self, _context):
+ pass
+
+
+class SEQUENCER_PT_overlay(Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_label = "Overlays"
+ bl_ui_units_x = 7
+
+ def draw(self, _context):
+ pass
+
+
+class SEQUENCER_PT_preview_overlay(Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'SEQUENCER_PT_overlay'
+ bl_label = "Preview Overlays"
+
+ @classmethod
+ def poll(cls, context):
+ st = context.space_data
+ return st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'} and st.display_mode == 'IMAGE'
+
+ def draw(self, context):
+ ed = context.scene.sequence_editor
+ st = context.space_data
+ layout = self.layout
+
+ layout.active = st.show_strip_overlay
+ layout.prop(ed, "show_overlay", text="Frame Overlay")
+ layout.prop(st, "show_safe_areas", text="Safe Areas")
+ layout.prop(st, "show_metadata", text="Metadata")
+ layout.prop(st, "show_annotation", text="Annotations")
+
+
+class SEQUENCER_PT_sequencer_overlay(Panel):
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'SEQUENCER_PT_overlay'
+ bl_label = "Sequencer Overlays"
+
+ @classmethod
+ def poll(cls, context):
+ st = context.space_data
+ return st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}
+
+ def draw(self, context):
+ st = context.space_data
+ layout = self.layout
+
+ layout.active = st.show_strip_overlay
+
+ layout.prop(st, "show_strip_name", text="Name")
+ layout.prop(st, "show_strip_source", text="Source")
+ layout.prop(st, "show_strip_duration", text="Duration")
+
+ layout.separator()
+
+ layout.prop(st, "show_strip_offset", text="Offsets")
+ layout.prop(st, "show_fcurves", text="F-Curves")
+
+ layout.separator()
+
+ layout.prop_menu_enum(st, "waveform_display_type")
+
+
class SEQUENCER_MT_view_cache(Menu):
bl_label = "Cache"
@@ -294,6 +381,12 @@ class SEQUENCER_MT_view(Menu):
layout.operator("view2d.zoom_border", text="Zoom")
layout.menu("SEQUENCER_MT_preview_zoom")
+ if st.display_mode == 'IMAGE':
+ layout.prop(st, "use_zoom_to_fit")
+ elif st.display_mode == 'WAVEFORM':
+ layout.separator()
+ layout.prop(st, "show_separate_color", text="Show Separate Color Channels")
+
layout.separator()
layout.menu("SEQUENCER_MT_proxy")
@@ -318,22 +411,8 @@ class SEQUENCER_MT_view(Menu):
layout.separator()
layout.prop(st, "show_seconds")
- layout.prop(st, "show_strip_offset")
- layout.prop(st, "show_fcurves")
layout.prop(st, "show_markers")
layout.menu("SEQUENCER_MT_view_cache", text="Show Cache")
- layout.prop_menu_enum(st, "waveform_display_type", text="Show Waveforms")
-
- if is_preview:
- layout.separator()
- if st.display_mode == 'IMAGE':
- layout.prop(st, "use_zoom_to_fit")
- layout.prop(ed, "show_overlay", text="Show Frame Overlay")
- layout.prop(st, "show_safe_areas", text="Show Safe Areas")
- layout.prop(st, "show_metadata", text="Show Metadata")
- layout.prop(st, "show_annotation", text="Show Annotations")
- elif st.display_mode == 'WAVEFORM':
- layout.prop(st, "show_separate_color", text="Show Separate Color Channels")
layout.separator()
@@ -629,6 +708,22 @@ class SEQUENCER_MT_add_effect(Menu):
col.enabled = selected_sequences_len(context) != 0
+class SEQUENCER_MT_strip_image_transform(Menu):
+ bl_label = "Image Transform"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("sequencer.strip_transform_fit", text="Scale To Fit").fit_method = 'FIT'
+ layout.operator("sequencer.strip_transform_fit", text="Scale to Fill").fit_method = 'FILL'
+ layout.operator("sequencer.strip_transform_fit", text="Stretch To Fill").fit_method = 'STRETCH'
+ layout.separator()
+
+ layout.operator("sequencer.strip_transform_clear", text="Clear Position").property = 'POSITION'
+ layout.operator("sequencer.strip_transform_clear", text="Clear Scale").property = 'SCALE'
+ layout.operator("sequencer.strip_transform_clear", text="Clear Rotation").property = 'ROTATION'
+ layout.operator("sequencer.strip_transform_clear", text="Clear All").property = 'ALL'
+
class SEQUENCER_MT_strip_transform(Menu):
bl_label = "Transform"
@@ -723,6 +818,7 @@ class SEQUENCER_MT_strip(Menu):
layout.separator()
layout.menu("SEQUENCER_MT_strip_transform")
+ layout.menu("SEQUENCER_MT_strip_image_transform")
layout.separator()
layout.operator("sequencer.split", text="Split").type = 'SOFT'
@@ -2214,6 +2310,7 @@ classes = (
SEQUENCER_MT_strip_effect,
SEQUENCER_MT_strip_movie,
SEQUENCER_MT_strip,
+ SEQUENCER_MT_strip_image_transform,
SEQUENCER_MT_strip_transform,
SEQUENCER_MT_strip_input,
SEQUENCER_MT_strip_lock_mute,
@@ -2222,6 +2319,10 @@ classes = (
SEQUENCER_PT_active_tool,
SEQUENCER_PT_strip,
+ SEQUENCER_PT_overlay,
+ SEQUENCER_PT_preview_overlay,
+ SEQUENCER_PT_sequencer_overlay,
+
SEQUENCER_PT_effect,
SEQUENCER_PT_scene,
SEQUENCER_PT_mask,
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 16b02db9377..3b9ce5311f3 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -297,6 +297,7 @@ class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel):
col.label(text="New Keyframe Type")
col.prop(tool_settings, "keyframe_type", text="")
+
class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel):
bl_label = "Auto Keyframing"
bl_options = {'HIDE_HEADER'}
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index a69e3974193..0411d5c64bc 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -2903,10 +2903,10 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_sequencer_generic.blade,
],
'SEQUENCER_PREVIEW': [
- _defs_sequencer_generic.sample,
*_tools_select,
- *_tools_annotate,
_defs_sequencer_generic.blade,
+ _defs_sequencer_generic.sample,
+ *_tools_annotate,
],
}
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index ae45b9799f1..0167f0b1e20 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -211,7 +211,7 @@ class USERPREF_PT_interface_display(InterfacePanel, CenterAlignMixIn, Panel):
col.separator()
col = layout.column(heading="Tooltips", align=True)
- col.prop(view, "show_tooltips", text = "User Tooltips")
+ col.prop(view, "show_tooltips", text="User Tooltips")
sub = col.column()
sub.active = view.show_tooltips
sub.prop(view, "show_tooltips_python")
@@ -1362,14 +1362,15 @@ class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel):
row.separator()
row.label(text="Path")
- subrow = row.row()
- subrow.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False)
for i, library in enumerate(paths.asset_libraries):
name_col.prop(library, "name", text="")
row = path_col.row()
row.prop(library, "path", text="")
row.operator("preferences.asset_library_remove", text="", icon='X', emboss=False).index = i
+ row = box.row()
+ row.alignment = 'LEFT'
+ row.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False)
# -----------------------------------------------------------------------------
@@ -1881,12 +1882,12 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
is_visible = is_visible and is_enabled
if is_visible:
- if search and search not in info["name"].lower():
- if info["author"]:
- if search not in info["author"].lower():
- continue
- else:
- continue
+ if search and not (
+ (search in info["name"].lower()) or
+ (info["author"] and (search in info["author"].lower())) or
+ ((filter == "All") and (search in info["category"].lower()))
+ ):
+ continue
# Skip 2.7x add-ons included with Blender, unless in debug mode.
is_addon_27x = info.get("blender", (0,)) < (2, 80)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index c97d5601a10..8b5183faf62 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -5306,6 +5306,7 @@ class VIEW3D_MT_sculpt_mask_edit_pie(Menu):
op.filter_type = 'CONTRAST_DECREASE'
op.auto_iteration_count = False
+
class VIEW3D_MT_sculpt_automasking_pie(Menu):
bl_label = "Automasking"
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 293d55a6015..577f9678a62 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -966,6 +966,7 @@ class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
row.active = mesh.use_mirror_vertex_group_x
row.prop(mesh, "use_mirror_topology")
+
class VIEW3D_PT_tools_weightpaint_symmetry_for_topbar(Panel):
bl_space_type = 'TOPBAR'
bl_region_type = 'HEADER'
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index f1b783f31a5..c3ab1b3db97 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -481,10 +481,11 @@ def not_implemented_node(idname):
geometry_node_categories = [
# Geometry Nodes
GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
- NodeItem("GeometryNodeRandomAttribute"),
+ NodeItem("GeometryNodeAttributeRandomize"),
NodeItem("GeometryNodeAttributeMath"),
NodeItem("GeometryNodeAttributeFill"),
NodeItem("GeometryNodeAttributeMix"),
+ NodeItem("GeometryNodeAttributeColorRamp"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeValToRGB"),
diff --git a/release/steam/README.md b/release/steam/README.md
new file mode 100644
index 00000000000..05eda799c3f
--- /dev/null
+++ b/release/steam/README.md
@@ -0,0 +1,70 @@
+Creating Steam builds for Blender
+=================================
+
+This script automates creation of the Steam files: download of the archives,
+extraction of the archives, preparation of the build scripts (VDF files), actual
+building of the Steam game files.
+
+Requirements
+============
+
+* MacOS machine - Tested on Catalina 10.15.6. Extracting contents from the DMG
+ archive did not work Windows nor on Linux using 7-zip. All DMG archives tested
+ failed to be extracted. As such only MacOS is known to work.
+* Steam SDK downloaded from SteamWorks - The `steamcmd` is used to generate the
+ Steam game files. The path to the `steamcmd` is what is actually needed.
+* SteamWorks credentials - Needed to log in using `steamcmd`.
+* Login to SteamWorks with the `steamcmd` from the command-line at least once -
+ Needded to ensure the user is properly logged in. On a new machine the user
+ will have to go through two-factor authentication.
+* App ID and Depot IDs - Needed to create the VDF files.
+* Python 3.x - 3.7 was tested.
+* Base URL - for downloading the archives.
+
+Usage
+=====
+
+```bash
+$ export STEAMUSER=SteamUserName
+$ export STEAMPW=SteamUserPW
+$ export BASEURL=https://download.blender.org/release/Blender2.83/
+$ export VERSION=2.83.3
+$ export APPID=appidnr
+$ export WINID=winidnr
+$ export LINID=linuxidnr
+$ export MACOSID=macosidnr
+
+# log in to SteamWorks from command-line at least once
+
+$ ../sdk/tools/ContentBuilder/builder_osx/steamcmd +login $STEAMUSER $STEAMPW
+
+# once that has been done we can now actually start our tool
+
+$ python3.7 create_steam_builds.py --baseurl $BASEURL --version $VERSION --appid $APPID --winid $WINID --linuxid $LINID --macosid $MACOSID --steamuser $STEAMUSER --steampw $STEAMPW --steamcmd ../sdk/tools/ContentBuilder/builder_osx/steamcmd
+```
+
+All arguments in the above example are required.
+
+At the start the tool will login using `steamcmd`. This is necessary to let the
+Steam SDK update itself if necessary.
+
+There are a few optional arguments:
+
+* `--dryrun`: If set building the game files will not actually happen. A set of
+ log files and a preview manifest per depot will be created in the output folder.
+ This can be used to double-check everything works as expected.
+* `--skipdl`: If set will skip downloading of the archives. The tool expects the
+ archives to already exist in the correct content location.
+* `--skipextract`: If set will skip extraction of all archives. The tool expects
+ the archives to already have been correctly extracted in the content location.
+
+Run the tool with `-h` for detailed information on each argument.
+
+The content and output folders are generated through appending the version
+without dots to the words `content` and `output` respectively, e.g. `content2833`
+and `output2833`. These folders are created next to the tool.
+
+From all `.template` files the Steam build scripts will be generated also in the
+same directory as the tool. The files will have the extension `.vdf`.
+
+In case of errors the tool will have a non-zero return code. \ No newline at end of file
diff --git a/release/steam/blender_app_build.vdf.template b/release/steam/blender_app_build.vdf.template
new file mode 100644
index 00000000000..9e2d0625d72
--- /dev/null
+++ b/release/steam/blender_app_build.vdf.template
@@ -0,0 +1,17 @@
+"appbuild"
+{
+ "appid" "[APPID]"
+ "desc" "Blender [VERSION]" // description for this build
+ "buildoutput" "./[OUTPUT]" // build output folder for .log, .csm & .csd files, relative to location of this file
+ "contentroot" "./[CONTENT]" // root content folder, relative to location of this file
+ "setlive" "" // branch to set live after successful build, non if empty
+ "preview" "[DRYRUN]" // 1 to enable preview builds, 0 to commit build to steampipe
+ "local" "" // set to flie path of local content server
+
+ "depots"
+ {
+ "[WINID]" "depot_build_win.vdf"
+ "[LINUXID]" "depot_build_linux.vdf"
+ "[MACOSID]" "depot_build_macos.vdf"
+ }
+}
diff --git a/release/steam/create_steam_builds.py b/release/steam/create_steam_builds.py
new file mode 100644
index 00000000000..2ecd0c347f7
--- /dev/null
+++ b/release/steam/create_steam_builds.py
@@ -0,0 +1,397 @@
+#!/usr/bin/env python3
+
+import argparse
+import pathlib
+import requests
+import shutil
+import subprocess
+from typing import Callable, Iterator, List, Tuple
+
+# supported archive and platform endings, used to create actual archive names
+archive_endings = ["windows64.zip", "linux64.tar.xz", "macOS.dmg"]
+
+
+def add_optional_argument(option: str, help: str) -> None:
+ global parser
+ """Add an optional argument
+
+ Args:
+ option (str): Option to add
+ help (str): Help description for the argument
+ """
+ parser.add_argument(option, help=help, action='store_const', const=1)
+
+
+def blender_archives(version: str) -> Iterator[str]:
+ """Generator for Blender archives for version.
+
+ Yields for items in archive_endings an archive name in the form of
+ blender-{version}-{ending}.
+
+ Args:
+ version (str): Version string of the form 2.83.2
+
+
+ Yields:
+ Iterator[str]: Name in the form of blender-{version}-{ending}
+ """
+ global archive_endings
+
+ for ending in archive_endings:
+ yield f"blender-{version}-{ending}"
+
+
+def get_archive_type(archive_type: str, version: str) -> str:
+ """Return the archive of given type and version.
+
+ Args:
+ archive_type (str): extension for archive type to check for
+ version (str): Version string in the form 2.83.2
+
+ Raises:
+ Exception: Execption when archive type isn't found
+
+ Returns:
+ str: archive name for given type
+ """
+
+ for archive in blender_archives(version):
+ if archive.endswith(archive_type):
+ return archive
+ raise Exception("Unknown archive type")
+
+
+def execute_command(cmd: List[str], name: str, errcode: int, cwd=".", capture_output=True) -> str:
+ """Execute the given command.
+
+ Returns the process stdout upon success if any.
+
+ On error print message the command with name that has failed. Print stdout
+ and stderr of the process if any, and then exit with given error code.
+
+ Args:
+ cmd (List[str]): Command in list format, each argument as their own item
+ name (str): Name of command to use when printing to command-line
+ errcode (int): Error code to use in case of exit()
+ cwd (str, optional): Folder to use as current work directory for command
+ execution. Defaults to ".".
+ capture_output (bool, optional): Whether to capture command output or not.
+ Defaults to True.
+
+ Returns:
+ str: stdout if any, or empty string
+ """
+ cmd_process = subprocess.run(
+ cmd, capture_output=capture_output, encoding="UTF-8", cwd=cwd)
+ if cmd_process.returncode == 0:
+ if cmd_process.stdout:
+ return cmd_process.stdout
+ else:
+ return ""
+ else:
+ print(f"ERROR: {name} failed.")
+ if cmd_process.stdout:
+ print(cmd_process.stdout)
+ if cmd_process.stderr:
+ print(cmd_process.stderr)
+ exit(errcode)
+ return ""
+
+
+def download_archives(base_url: str, archives: Callable[[str], Iterator[str]], version: str, dst_dir: pathlib.Path):
+ """Download archives from the given base_url.
+
+ Archives is a generator for Blender archive names based on version.
+
+ Archive names are appended to the base_url to load from, and appended to
+ dst_dir to save to.
+
+ Args:
+ base_url (str): Base URL to load archives from
+ archives (Callable[[str], Iterator[str]]): Generator for Blender archive
+ names based on version
+ version (str): Version string in the form of 2.83.2
+ dst_dir (pathlib.Path): Download destination
+ """
+
+ if base_url[-1] != '/':
+ base_url = base_url + '/'
+
+ for archive in archives(version):
+ download_url = f"{base_url}{archive}"
+ target_file = dst_dir.joinpath(archive)
+ download_file(download_url, target_file)
+
+
+def download_file(from_url: str, to_file: pathlib.Path) -> None:
+ """Download from_url as to_file.
+
+ Actual downloading will be skipped if --skipdl is given on the command-line.
+
+ Args:
+ from_url (str): Full URL to resource to download
+ to_file (pathlib.Path): Full path to save downloaded resource as
+ """
+ global args
+
+ if not args.skipdl or not to_file.exists():
+ print(f"Downloading {from_url}")
+ with open(to_file, "wb") as download_zip:
+ response = requests.get(from_url)
+ if response.status_code != requests.codes.ok:
+ print(f"ERROR: failed to download {from_url} (status code: {response.status_code})")
+ exit(1313)
+ download_zip.write(response.content)
+ else:
+ print(f"Downloading {from_url} skipped")
+ print(" ... OK")
+
+
+def copy_contents_from_dmg_to_path(dmg_file: pathlib.Path, dst: pathlib.Path) -> None:
+ """Copy the contents of the given DMG file to the destination folder.
+
+ Args:
+ dmg_file (pathlib.Path): Full path to DMG archive to extract from
+ dst (pathlib.Path): Full path to destination to extract to
+ """
+ hdiutil_attach = ["hdiutil",
+ "attach",
+ "-readonly",
+ f"{dmg_file}"
+ ]
+ attached = execute_command(hdiutil_attach, "hdiutil attach", 1)
+
+ # Last line of output is what we want, it is of the form
+ # /dev/somedisk Apple_HFS /Volumes/Blender
+ # We want to retain the mount point, and the folder the mount is
+ # created on. The mounted disk we need for detaching, the folder we
+ # need to be able to copy the contents to where we can use them
+ attachment_items = attached.splitlines()[-1].split()
+ mounted_disk = attachment_items[0]
+ source_location = pathlib.Path(attachment_items[2], "Blender.app")
+
+ print(f"{source_location} -> {dst}")
+
+ shutil.copytree(source_location, dst)
+
+ hdiutil_detach = ["hdiutil",
+ "detach",
+ f"{mounted_disk}"
+ ]
+ execute_command(hdiutil_detach, "hdiutil detach", 2)
+
+
+def create_build_script(template_name: str, vars: List[Tuple[str, str]]) -> pathlib.Path:
+ """
+ Create the Steam build script
+
+ Use the given template and template variable tuple list.
+
+ Returns pathlib.Path to the created script.
+
+ Args:
+ template_name (str): [description]
+ vars (List[Tuple[str, str]]): [description]
+
+ Returns:
+ pathlib.Path: Full path to the generated script
+ """
+ build_script = pathlib.Path(".", template_name).read_text()
+ for var in vars:
+ build_script = build_script.replace(var[0], var[1])
+ build_script_file = template_name.replace(".template", "")
+ build_script_path = pathlib.Path(".", build_script_file)
+ build_script_path.write_text(build_script)
+ return build_script_path
+
+
+def clean_up() -> None:
+ """Remove intermediate files depending on given command-line arguments
+ """
+ global content_location, args
+
+ if not args.leavearch and not args.leaveextracted:
+ shutil.rmtree(content_location)
+
+ if args.leavearch and not args.leaveextracted:
+ shutil.rmtree(content_location.joinpath(zip_extract_folder))
+ shutil.rmtree(content_location.joinpath(tarxz_extract_folder))
+ shutil.rmtree(content_location.joinpath(dmg_extract_folder))
+
+ if args.leaveextracted and not args.leavearch:
+ import os
+ os.remove(content_location.joinpath(zipped_blender))
+ os.remove(content_location.joinpath(tarxz_blender))
+ os.remove(content_location.joinpath(dmg_blender))
+
+
+def extract_archive(archive: str, extract_folder_name: str,
+ cmd: List[str], errcode: int) -> None:
+ """Extract all files from archive to given folder name.
+
+ Will not extract if
+ target folder already exists, or if --skipextract was given on the
+ command-line.
+
+ Args:
+ archive (str): Archive name to extract
+ extract_folder_name (str): Folder name to extract to
+ cmd (List[str]): Command with arguments to use
+ errcode (int): Error code to use for exit()
+ """
+ global args, content_location
+
+ extract_location = content_location.joinpath(extract_folder_name)
+
+ pre_extract = set(content_location.glob("*"))
+
+ if not args.skipextract or not extract_location.exists():
+ print(f"Extracting files from {archive}...")
+ cmd.append(content_location.joinpath(archive))
+ execute_command(cmd, cmd[0], errcode, cwd=content_location)
+ # in case we use a non-release archive the naming will be incorrect.
+ # simply rename to expected target name
+ post_extract = set(content_location.glob("*"))
+ diff_extract = post_extract - pre_extract
+ if not extract_location in diff_extract:
+ folder_to_rename = list(diff_extract)[0]
+ folder_to_rename.rename(extract_location)
+ print(" OK")
+ else:
+ print(f"Skipping extraction {archive}!")
+
+# ==============================================================================
+
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument("--baseurl", required=True,
+ help="The base URL for files to download, "
+ "i.e. https://download.blender.org/release/Blender2.83/")
+
+parser.add_argument("--version", required=True,
+ help="The Blender version to release, in the form 2.83.3")
+
+parser.add_argument("--appid", required=True,
+ help="The Blender App ID on Steam")
+parser.add_argument("--winid", required=True,
+ help="The Windows depot ID")
+parser.add_argument("--linuxid", required=True,
+ help="The Linux depot ID")
+parser.add_argument("--macosid", required=True,
+ help="The MacOS depot ID")
+
+parser.add_argument("--steamcmd", required=True,
+ help="Path to the steamcmd")
+parser.add_argument("--steamuser", required=True,
+ help="The login for the Steam builder user")
+parser.add_argument("--steampw", required=True,
+ help="Login password for the Steam builder user")
+
+add_optional_argument("--dryrun",
+ "If set the Steam files will not be uploaded")
+add_optional_argument("--leavearch",
+ help="If set don't clean up the downloaded archives")
+add_optional_argument("--leaveextracted",
+ help="If set don't clean up the extraction folders")
+add_optional_argument("--skipdl",
+ help="If set downloading the archives is skipped if it already exists locally.")
+add_optional_argument("--skipextract",
+ help="If set skips extracting of archives. The tool assumes the archives"
+ "have already been extracted to their correct locations")
+
+args = parser.parse_args()
+
+VERSIONNODOTS = args.version.replace('.', '')
+OUTPUT = f"output{VERSIONNODOTS}"
+CONTENT = f"content{VERSIONNODOTS}"
+
+# ===== set up main locations
+
+content_location = pathlib.Path(".", CONTENT).absolute()
+output_location = pathlib.Path(".", OUTPUT).absolute()
+
+content_location.mkdir(parents=True, exist_ok=True)
+output_location.mkdir(parents=True, exist_ok=True)
+
+# ===== login
+
+# Logging into Steam once to ensure the SDK updates itself properly. If we don't
+# do that the combined +login and +run_app_build_http at the end of the tool
+# will fail.
+steam_login = [args.steamcmd,
+ "+login",
+ args.steamuser,
+ args.steampw,
+ "+quit"
+ ]
+print("Logging in to Steam...")
+execute_command(steam_login, "Login to Steam", 10)
+print(" OK")
+
+# ===== prepare Steam build scripts
+
+template_vars = [
+ ("[APPID]", args.appid),
+ ("[OUTPUT]", OUTPUT),
+ ("[CONTENT]", CONTENT),
+ ("[VERSION]", args.version),
+ ("[WINID]", args.winid),
+ ("[LINUXID]", args.linuxid),
+ ("[MACOSID]", args.macosid),
+ ("[DRYRUN]", f"{args.dryrun}" if args.dryrun else "0")
+]
+
+blender_app_build = create_build_script(
+ "blender_app_build.vdf.template", template_vars)
+create_build_script("depot_build_win.vdf.template", template_vars)
+create_build_script("depot_build_linux.vdf.template", template_vars)
+create_build_script("depot_build_macos.vdf.template", template_vars)
+
+# ===== download archives
+
+download_archives(args.baseurl, blender_archives,
+ args.version, content_location)
+
+# ===== set up file and folder names
+
+zipped_blender = get_archive_type("zip", args.version)
+zip_extract_folder = zipped_blender.replace(".zip", "")
+tarxz_blender = get_archive_type("tar.xz", args.version)
+tarxz_extract_folder = tarxz_blender.replace(".tar.xz", "")
+dmg_blender = get_archive_type("dmg", args.version)
+dmg_extract_folder = dmg_blender.replace(".dmg", "")
+
+# ===== extract
+
+unzip_cmd = ["unzip", "-q"]
+extract_archive(zipped_blender, zip_extract_folder, unzip_cmd, 3)
+
+untarxz_cmd = ["tar", "-xf"]
+extract_archive(tarxz_blender, tarxz_extract_folder, untarxz_cmd, 4)
+
+if not args.skipextract or not content_location.joinpath(dmg_extract_folder).exists():
+ print("Extracting files from Blender MacOS archive...")
+ blender_dmg = content_location.joinpath(dmg_blender)
+ target_location = content_location.joinpath(
+ dmg_extract_folder, "Blender.app")
+ copy_contents_from_dmg_to_path(blender_dmg, target_location)
+ print(" OK")
+else:
+ print("Skipping extraction of .dmg!")
+
+# ===== building
+
+print("Build Steam game files...")
+steam_build = [args.steamcmd,
+ "+login",
+ args.steamuser,
+ args.steampw,
+ "+run_app_build_http",
+ blender_app_build.absolute(),
+ "+quit"
+ ]
+execute_command(steam_build, "Build with steamcmd", 13)
+print(" OK")
+
+clean_up()
diff --git a/release/steam/depot_build_linux.vdf.template b/release/steam/depot_build_linux.vdf.template
new file mode 100644
index 00000000000..0f69008548e
--- /dev/null
+++ b/release/steam/depot_build_linux.vdf.template
@@ -0,0 +1,31 @@
+"DepotBuildConfig"
+{
+ // Set your assigned depot ID here
+ "DepotID" "[LINUXID]"
+
+ // Set a root for all content.
+ // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths)
+ // will be resolved relative to this root.
+ // If you don't define ContentRoot, then it will be assumed to be
+ // the location of this script file, which probably isn't what you want
+ "ContentRoot" "./blender-[VERSION]-linux64/"
+
+ // include all files recursivley
+ "FileMapping"
+ {
+ // This can be a full path, or a path relative to ContentRoot
+ "LocalPath" "*"
+
+ // This is a path relative to the install folder of your game
+ "DepotPath" "."
+
+ // If LocalPath contains wildcards, setting this means that all
+ // matching files within subdirectories of LocalPath will also
+ // be included.
+ "recursive" "1"
+ }
+
+ // but exclude all symbol files
+ // This can be a full path, or a path relative to ContentRoot
+ "FileExclusion" "*.pdb"
+}
diff --git a/release/steam/depot_build_macos.vdf.template b/release/steam/depot_build_macos.vdf.template
new file mode 100644
index 00000000000..33dde860462
--- /dev/null
+++ b/release/steam/depot_build_macos.vdf.template
@@ -0,0 +1,30 @@
+"DepotBuildConfig"
+{
+ // Set your assigned depot ID here
+ "DepotID" "[MACOSID]"
+
+ // Set a root for all content.
+ // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths)
+ // will be resolved relative to this root.
+ // If you don't define ContentRoot, then it will be assumed to be
+ // the location of this script file, which probably isn't what you want
+ "ContentRoot" "./blender-[VERSION]-macOS/"
+ // include all files recursivley
+ "FileMapping"
+ {
+ // This can be a full path, or a path relative to ContentRoot
+ "LocalPath" "*"
+
+ // This is a path relative to the install folder of your game
+ "DepotPath" "."
+
+ // If LocalPath contains wildcards, setting this means that all
+ // matching files within subdirectories of LocalPath will also
+ // be included.
+ "recursive" "1"
+ }
+
+ // but exclude all symbol files
+ // This can be a full path, or a path relative to ContentRoot
+ "FileExclusion" "*.pdb"
+}
diff --git a/release/steam/depot_build_win.vdf.template b/release/steam/depot_build_win.vdf.template
new file mode 100644
index 00000000000..2c18a0f15dd
--- /dev/null
+++ b/release/steam/depot_build_win.vdf.template
@@ -0,0 +1,31 @@
+"DepotBuildConfig"
+{
+ // Set your assigned depot ID here
+ "DepotID" "[WINID]"
+
+ // Set a root for all content.
+ // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths)
+ // will be resolved relative to this root.
+ // If you don't define ContentRoot, then it will be assumed to be
+ // the location of this script file, which probably isn't what you want
+ "ContentRoot" "./blender-[VERSION]-windows64/"
+
+ // include all files recursivley
+ "FileMapping"
+ {
+ // This can be a full path, or a path relative to ContentRoot
+ "LocalPath" "*"
+
+ // This is a path relative to the install folder of your game
+ "DepotPath" "."
+
+ // If LocalPath contains wildcards, setting this means that all
+ // matching files within subdirectories of LocalPath will also
+ // be included.
+ "recursive" "1"
+ }
+
+ // but exclude all symbol files
+ // This can be a full path, or a path relative to ContentRoot
+ "FileExclusion" "*.pdb"
+}
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index 51d3849aa48..25235097505 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -47,6 +47,9 @@
#include "blf_internal.h"
#include "blf_internal_types.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
static ListBase global_font_dir = {NULL, NULL};
static DirBLF *blf_dir_find(const char *path)
@@ -137,9 +140,11 @@ char *blf_dir_search(const char *file)
}
if (!s) {
- /* check the current directory, why not ? */
- if (BLI_exists(file)) {
- s = BLI_strdup(file);
+ /* Assume file is either an abslute path, or a relative path to current directory. */
+ BLI_strncpy(full_path, file, sizeof(full_path));
+ BLI_path_abs(full_path, BKE_main_blendfile_path(G_MAIN));
+ if (BLI_exists(full_path)) {
+ s = BLI_strdup(full_path);
}
}
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index d8605941974..717cfa607ad 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -30,10 +30,10 @@
extern "C" {
#endif
-struct BlendWriter;
struct BlendDataReader;
-struct BlendLibReader;
struct BlendExpander;
+struct BlendLibReader;
+struct BlendWriter;
struct bArmature;
/* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */
diff --git a/source/blender/blenkernel/BKE_anim_visualization.h b/source/blender/blenkernel/BKE_anim_visualization.h
index decb2e0b210..4e86abeed8d 100644
--- a/source/blender/blenkernel/BKE_anim_visualization.h
+++ b/source/blender/blenkernel/BKE_anim_visualization.h
@@ -26,14 +26,14 @@
extern "C" {
#endif
+struct BlendDataReader;
+struct BlendWriter;
struct Object;
struct ReportList;
struct Scene;
struct bAnimVizSettings;
struct bMotionPath;
struct bPoseChannel;
-struct BlendWriter;
-struct BlendDataReader;
/* ---------------------------------------------------- */
/* Animation Visualization */
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index e812d04c7d1..8d904bd6019 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -45,8 +45,6 @@ struct NlaKeyframingContext;
struct PathResolvedRNA;
struct PointerRNA;
struct PropertyRNA;
-struct ReportList;
-struct Scene;
struct bAction;
struct bActionGroup;
struct bContext;
diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h
index 20df6109c13..38cd5747343 100644
--- a/source/blender/blenkernel/BKE_asset.h
+++ b/source/blender/blenkernel/BKE_asset.h
@@ -27,8 +27,8 @@
extern "C" {
#endif
-struct BlendWriter;
struct BlendDataReader;
+struct BlendWriter;
struct ID;
struct PreviewImage;
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 55a841d8fd1..574d9904dc4 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -35,7 +35,6 @@ extern "C" {
struct CustomData;
struct CustomDataLayer;
struct ID;
-struct PointerRNA;
struct ReportList;
/* Attribute.domain */
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index c4a704ef385..eafd86d176b 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -26,8 +26,6 @@
#include "BLI_color.hh"
#include "BLI_float3.hh"
-struct Mesh;
-
namespace blender::bke {
using fn::CPPType;
@@ -266,9 +264,11 @@ template<typename T> class TypedWriteAttribute {
}
};
+using BooleanReadAttribute = TypedReadAttribute<bool>;
using FloatReadAttribute = TypedReadAttribute<float>;
using Float3ReadAttribute = TypedReadAttribute<float3>;
using Color4fReadAttribute = TypedReadAttribute<Color4f>;
+using BooleanWriteAttribute = TypedWriteAttribute<bool>;
using FloatWriteAttribute = TypedWriteAttribute<float>;
using Float3WriteAttribute = TypedWriteAttribute<float3>;
using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index afb6112b954..1ed4d1183a1 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 6
+#define BLENDER_FILE_SUBVERSION 8
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index a10a4e3c7fd..ff1bca896b1 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -26,9 +26,9 @@
extern "C" {
#endif
+struct BVHTree;
struct Collection;
struct CollisionModifierData;
-struct BVHTree;
struct Depsgraph;
struct MVert;
struct MVertTri;
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 7a14787c191..afad1e26159 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -23,6 +23,10 @@
* \ingroup bke
*/
+struct BlendDataReader;
+struct BlendExpander;
+struct BlendLibReader;
+struct BlendWriter;
struct Depsgraph;
struct ID;
struct ListBase;
@@ -31,10 +35,6 @@ struct Scene;
struct bConstraint;
struct bConstraintTarget;
struct bPoseChannel;
-struct BlendWriter;
-struct BlendDataReader;
-struct BlendLibReader;
-struct BlendExpander;
/* ---------------------------------------------------------------------------- */
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index 71b15e47203..433c25084ad 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -29,10 +29,9 @@
extern "C" {
#endif
-struct Object;
-struct Material;
-struct ID;
struct Main;
+struct Material;
+struct Object;
uint32_t BKE_cryptomatte_hash(const char *name, int name_len);
uint32_t BKE_cryptomatte_object_hash(const struct Object *object);
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 0c84ad70845..2fb713a4299 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -35,9 +35,7 @@ struct BMLoop;
struct BMesh;
struct BoundBox;
struct Depsgraph;
-struct EditMeshData;
struct Mesh;
-struct MeshStatVis;
struct Object;
struct Scene;
diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h
index 87bb96be145..37a3ed82bb8 100644
--- a/source/blender/blenkernel/BKE_geometry_set.h
+++ b/source/blender/blenkernel/BKE_geometry_set.h
@@ -24,9 +24,9 @@
extern "C" {
#endif
-struct Object;
-struct GeometrySet;
struct Collection;
+struct GeometrySet;
+struct Object;
void BKE_geometry_set_free(struct GeometrySet *geometry_set);
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 617e0c45ae4..90d444aa270 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -32,10 +32,10 @@
#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.h"
+struct Collection;
struct Mesh;
-struct PointCloud;
struct Object;
-struct Collection;
+struct PointCloud;
/* Each geometry component has a specific type. The type determines what kind of data the component
* stores. Functions modifying a geometry will usually just modify a subset of the component types.
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 6dc8d1ef06e..df5711f5120 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -36,19 +36,17 @@ struct ListBase;
struct MDeformVert;
struct Main;
struct Material;
-struct MaterialGPencilStyle;
struct Object;
struct Scene;
struct SpaceImage;
struct ToolSettings;
struct ViewLayer;
struct bDeformGroup;
+struct bGPDcurve;
struct bGPDframe;
struct bGPDlayer;
struct bGPDlayer_Mask;
-struct bGPDspoint;
struct bGPDstroke;
-struct bGPDcurve;
struct bGPdata;
#define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
index 1821972469c..2d42bb36949 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -30,10 +30,10 @@ extern "C" {
struct Main;
struct Object;
struct Scene;
-struct bGPdata;
+struct bGPDcurve;
struct bGPDlayer;
struct bGPDstroke;
-struct bGPDcurve;
+struct bGPdata;
void BKE_gpencil_convert_curve(struct Main *bmain,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 111f9030463..1c86df73d3c 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -32,12 +32,11 @@ struct Depsgraph;
struct Main;
struct Object;
struct Scene;
+struct bGPDcurve;
struct bGPDframe;
-struct bGPDlayer;
struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
-struct bGPDcurve;
/* Object boundbox. */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index ccf65a585ef..61ccf3d60f6 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -27,6 +27,9 @@ extern "C" {
#endif
struct ARegionType;
+struct BlendDataReader;
+struct BlendLibReader;
+struct BlendWriter;
struct Depsgraph;
struct GpencilModifierData;
struct ID;
@@ -35,9 +38,6 @@ struct Main;
struct ModifierUpdateDepsgraphContext;
struct Object;
struct Scene;
-struct BlendWriter;
-struct BlendDataReader;
-struct BlendLibReader;
/* NOTE: bakeModifier() called from UI:
* needs to create new data-blocks, hence the need for this. */
struct bGPDframe;
diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h
index 40b9f738bfd..f4871c83caf 100644
--- a/source/blender/blenkernel/BKE_ipo.h
+++ b/source/blender/blenkernel/BKE_ipo.h
@@ -26,7 +26,6 @@
extern "C" {
#endif
-struct Ipo;
struct Main;
void do_versions_ipos_to_animato(struct Main *main);
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index f4c1a6fdcb4..02fa8b306d3 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -38,7 +38,6 @@ struct Main;
struct Mesh;
struct Object;
struct Scene;
-struct bGPDstroke;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 9f3536c9314..b0971278dc7 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -51,7 +51,6 @@
extern "C" {
#endif
-struct BlendDataReader;
struct BlendWriter;
struct GHash;
struct ID;
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index bf6b5cbccef..13edabd4cb7 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -72,6 +72,7 @@ void BKE_lib_override_library_dependencies_tag(struct Main *bmain,
void BKE_lib_override_library_override_group_tag(struct Main *bmain,
struct ID *id_root,
const uint tag,
+ const uint missing_tag,
const bool do_create_main_relashionships);
bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index fb14e340d8b..a8d75213d39 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -38,8 +38,6 @@
extern "C" {
#endif
-struct wmWindowManager;
-
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
/* Also IDRemap->flag. */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 0f34549a3cd..2d8dc852d7c 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -26,7 +26,6 @@
#include "BLI_utildefines.h"
struct BLI_Stack;
-struct BMEditMesh;
struct BMesh;
struct BMeshCreateParams;
struct BMeshFromMeshParams;
diff --git a/source/blender/blenkernel/BKE_mesh_fair.h b/source/blender/blenkernel/BKE_mesh_fair.h
new file mode 100644
index 00000000000..2d5c85d4129
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_fair.h
@@ -0,0 +1,56 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing":
+ * https://github.com/fedackb/mesh-fairing.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_utildefines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Mesh Fairing. */
+/* Creates a smooth as possible geometry patch in a defined area. Different values of depth allow
+ * to minimize changes in the vertex positions or tangency in the affected area. */
+
+typedef enum eMeshFairingDepth {
+ MESH_FAIRING_DEPTH_POSITION = 1,
+ MESH_FAIRING_DEPTH_TANGENCY = 2,
+} eMeshFairingDepth;
+
+/* affect_vertices is used to define the fairing area. Indexed by vertex index, set to true when
+ * the vertex should be modified by fairing. */
+void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm,
+ bool *affect_vertices,
+ const eMeshFairingDepth depth);
+
+/* This function can optionally use the MVert coordinates of deform_mverts to read and write the
+ * fairing result. When NULL, the function will use mesh->mverts directly. */
+void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh,
+ struct MVert *deform_mverts,
+ bool *affect_vertices,
+ const eMeshFairingDepth depth);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 38b449cd92d..685a8ed98e2 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -35,6 +35,7 @@ struct BlendWriter;
struct CustomData_MeshMasks;
struct DepsNodeHandle;
struct Depsgraph;
+struct GeometrySet;
struct ID;
struct ListBase;
struct Main;
@@ -43,7 +44,6 @@ struct ModifierData;
struct Object;
struct Scene;
struct bArmature;
-struct GeometrySet;
typedef enum {
/* Should not be used, only for None modifier type */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 77a1d3989b0..5f69fc397e8 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1347,11 +1347,12 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_POINT_INSTANCE 1005
#define GEO_NODE_SUBDIVISION_SURFACE 1006
#define GEO_NODE_OBJECT_INFO 1007
-#define GEO_NODE_RANDOM_ATTRIBUTE 1008
+#define GEO_NODE_ATTRIBUTE_RANDOMIZE 1008
#define GEO_NODE_ATTRIBUTE_MATH 1009
#define GEO_NODE_JOIN_GEOMETRY 1010
#define GEO_NODE_ATTRIBUTE_FILL 1011
#define GEO_NODE_ATTRIBUTE_MIX 1012
+#define GEO_NODE_ATTRIBUTE_COLOR_RAMP 1013
/** \} */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 0a50dde1874..aaed2649ad9 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -34,6 +34,9 @@ extern "C" {
struct BMFace;
struct BMesh;
+struct BlendDataReader;
+struct BlendLibReader;
+struct BlendWriter;
struct Brush;
struct CurveMapping;
struct Depsgraph;
@@ -55,7 +58,6 @@ struct Paint;
struct PaintCurve;
struct Palette;
struct PaletteColor;
-struct ReportList;
struct Scene;
struct StrokeCache;
struct SubdivCCG;
@@ -67,9 +69,6 @@ struct ViewLayer;
struct bContext;
struct bToolRef;
struct tPaletteColorHSV;
-struct BlendWriter;
-struct BlendDataReader;
-struct BlendLibReader;
extern const char PAINT_CURSOR_SCULPT[3];
extern const char PAINT_CURSOR_VERTEX_PAINT[3];
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 2ac39be7eb3..3913ede9049 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -42,9 +42,9 @@ struct ParticleSystemModifierData;
struct BVHTreeRay;
struct BVHTreeRayHit;
-struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
+struct BlendWriter;
struct CustomData_MeshMasks;
struct Depsgraph;
struct EdgeHash;
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index fd600a41796..0fa44067b16 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -48,7 +48,6 @@ struct PBVH;
struct PBVHNode;
struct SubdivCCG;
struct TaskParallelSettings;
-struct TaskParallelTLS;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index d3ae043588d..170eb4ba662 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -77,7 +77,10 @@ extern "C" {
#define PTCACHE_READ_OLD 3
/* Structs */
+struct BlendDataReader;
+struct BlendWriter;
struct ClothModifierData;
+struct DynamicPaintSurface;
struct FluidModifierData;
struct ListBase;
struct Main;
@@ -89,9 +92,6 @@ struct RigidBodyWorld;
struct Scene;
struct SoftBody;
struct ViewLayer;
-struct BlendWriter;
-struct BlendDataReader;
-struct DynamicPaintSurface;
/* temp structure for read/write */
typedef struct PTCacheData {
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 473a684eaba..7b5df98d148 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -51,7 +51,6 @@ struct View3D;
struct View3DShading;
struct WorkSpace;
struct bContext;
-struct bContextDataResult;
struct bScreen;
struct uiLayout;
struct uiList;
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
index b5b5f61a6a6..23bd62c70bc 100644
--- a/source/blender/blenkernel/BKE_shader_fx.h
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -27,14 +27,14 @@ extern "C" {
#endif
struct ARegionType;
+struct BlendDataReader;
+struct BlendLibReader;
+struct BlendWriter;
struct ID;
struct ListBase;
struct ModifierUpdateDepsgraphContext;
struct Object;
struct ShaderFxData;
-struct BlendWriter;
-struct BlendDataReader;
-struct BlendLibReader;
#define SHADER_FX_ACTIVE(_fx, _is_render) \
((((_fx)->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h
index e288c9f3eb4..9defa887d3c 100644
--- a/source/blender/blenkernel/BKE_speaker.h
+++ b/source/blender/blenkernel/BKE_speaker.h
@@ -26,7 +26,6 @@ extern "C" {
#endif
struct Main;
-struct Speaker;
void *BKE_speaker_add(struct Main *bmain, const char *name);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 0067e1c8209..ae0a180311c 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -42,6 +42,7 @@ set(INC
../simulation
../../../intern/ghost
../../../intern/glew-mx
+ ../../../intern/eigen
../../../intern/guardedalloc
../../../intern/iksolver/extern
../../../intern/atomic
@@ -170,6 +171,7 @@ set(SRC
intern/mesh.c
intern/mesh_convert.c
intern/mesh_evaluate.c
+ intern/mesh_fair.cc
intern/mesh_iterators.c
intern/mesh_mapping.c
intern/mesh_merge.c
@@ -353,6 +355,7 @@ set(SRC
BKE_mball_tessellate.h
BKE_mesh.h
BKE_mesh_iterators.h
+ BKE_mesh_fair.h
BKE_mesh_mapping.h
BKE_mesh_mirror.h
BKE_mesh_remap.h
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index a6b3985e80d..ae0c27635a6 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -906,14 +906,20 @@ bool BKE_appdir_program_python_search(char *fullpath,
const char *python_build_def = STRINGIFY(PYTHON_EXECUTABLE_NAME);
#endif
const char *basename = "python";
+#if defined(WIN32) && !defined(NDEBUG)
+ const char *basename_debug = "python_d";
+#endif
char python_version[16];
/* Check both possible names. */
const char *python_names[] = {
#ifdef PYTHON_EXECUTABLE_NAME
- python_build_def,
+ python_build_def,
+#endif
+#if defined(WIN32) && !defined(NDEBUG)
+ basename_debug,
#endif
- python_version,
- basename,
+ python_version,
+ basename,
};
bool is_found = false;
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 282e9bc2962..623335f65a1 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -392,6 +392,8 @@ const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType ty
return &CPPType::get<int>();
case CD_PROP_COLOR:
return &CPPType::get<Color4f>();
+ case CD_PROP_BOOL:
+ return &CPPType::get<bool>();
default:
return nullptr;
}
@@ -415,6 +417,9 @@ CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type)
if (type.is<Color4f>()) {
return CD_PROP_COLOR;
}
+ if (type.is<bool>()) {
+ return CD_PROP_BOOL;
+ }
return static_cast<CustomDataType>(-1);
}
@@ -449,6 +454,9 @@ static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom
case CD_PROP_COLOR:
return std::make_unique<ArrayReadAttribute<Color4f>>(
domain, Span(static_cast<Color4f *>(layer.data), size));
+ case CD_PROP_BOOL:
+ return std::make_unique<ArrayReadAttribute<bool>>(
+ domain, Span(static_cast<bool *>(layer.data), size));
}
}
}
@@ -490,6 +498,9 @@ static WriteAttributePtr write_attribute_from_custom_data(
case CD_PROP_COLOR:
return std::make_unique<ArrayWriteAttribute<Color4f>>(
domain, MutableSpan(static_cast<Color4f *>(layer.data), size));
+ case CD_PROP_BOOL:
+ return std::make_unique<ArrayWriteAttribute<bool>>(
+ domain, MutableSpan(static_cast<bool *>(layer.data), size));
}
}
}
@@ -751,6 +762,7 @@ bool PointCloudComponent::attribute_domain_with_type_supported(
const AttributeDomain domain, const CustomDataType data_type) const
{
return domain == ATTR_DOMAIN_POINT && ELEM(data_type,
+ CD_PROP_BOOL,
CD_PROP_FLOAT,
CD_PROP_FLOAT2,
CD_PROP_FLOAT3,
@@ -874,8 +886,13 @@ bool MeshComponent::attribute_domain_with_type_supported(const AttributeDomain d
if (!this->attribute_domain_supported(domain)) {
return false;
}
- return ELEM(
- data_type, CD_PROP_FLOAT, CD_PROP_FLOAT2, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR);
+ return ELEM(data_type,
+ CD_PROP_BOOL,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_INT32,
+ CD_PROP_COLOR);
}
int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 33686cea4fc..9a954a89cad 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1834,6 +1834,14 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SPHERE;
break;
+ case SCULPT_TOOL_DISPLACEMENT_SMEAR:
+ br->alpha = 1.0f;
+ br->spacing = 5;
+ br->hardness = 0.7f;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->curve_preset = BRUSH_CURVE_SMOOTHER;
+ break;
default:
break;
}
@@ -1898,6 +1906,7 @@ void BKE_brush_sculpt_reset(Brush *br)
case SCULPT_TOOL_MASK:
case SCULPT_TOOL_DRAW_FACE_SETS:
case SCULPT_TOOL_DISPLACEMENT_ERASER:
+ case SCULPT_TOOL_DISPLACEMENT_SMEAR:
br->add_col[0] = 0.75f;
br->add_col[1] = 0.75f;
br->add_col[2] = 0.75f;
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index fdb3e246382..1e2bc570c65 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1837,6 +1837,21 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerMultiply_propfloat2,
NULL,
layerAdd_propfloat2},
+ /* 50: CD_PROP_POOL */
+ {sizeof(bool),
+ "bool",
+ 1,
+ N_("Boolean"),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL},
};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -1892,6 +1907,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDPropCol",
"CDPropFloat3",
"CDPropFloat2",
+ "CDPropBoolean",
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc
index 48f5e11778c..fbf69357478 100644
--- a/source/blender/blenkernel/intern/icons.cc
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -78,7 +78,7 @@ enum {
static CLG_LogRef LOG = {"bke.icons"};
/* Protected by gIconMutex. */
-static GHash *gIcons = NULL;
+static GHash *gIcons = nullptr;
/* Protected by gIconMutex. */
static int gNextIconId = 1;
@@ -89,7 +89,7 @@ static int gFirstIconId = 1;
std::mutex gIconMutex;
/* Not mutex-protected! */
-static GHash *gCachedPreviews = NULL;
+static GHash *gCachedPreviews = nullptr;
/* Queue of icons for deferred deletion. */
typedef struct DeferredIconDeleteNode {
@@ -149,7 +149,7 @@ static void icon_free_data(int icon_id, Icon *icon)
}
else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
StudioLight *sl = (StudioLight *)icon->obj;
- if (sl != NULL) {
+ if (sl != nullptr) {
BKE_studiolight_unset_icon_id(sl, icon_id);
}
}
@@ -166,7 +166,7 @@ static Icon *icon_ghash_lookup(int icon_id)
/* create an id for a new icon and make sure that ids from deleted icons get reused
* after the integer number range is used up */
-static int get_next_free_id(void)
+static int get_next_free_id()
{
std::scoped_lock lock(gIconMutex);
int startId = gFirstIconId;
@@ -214,13 +214,13 @@ void BKE_icons_free(void)
BLI_assert(BLI_thread_is_main());
if (gIcons) {
- BLI_ghash_free(gIcons, NULL, icon_free);
- gIcons = NULL;
+ BLI_ghash_free(gIcons, nullptr, icon_free);
+ gIcons = nullptr;
}
if (gCachedPreviews) {
BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
- gCachedPreviews = NULL;
+ gCachedPreviews = nullptr;
}
BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
@@ -232,9 +232,9 @@ void BKE_icons_deferred_free(void)
for (DeferredIconDeleteNode *node =
(DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue);
- node != NULL;
+ node != nullptr;
node = node->next) {
- BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), NULL, icon_free);
+ BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), nullptr, icon_free);
}
BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN);
}
@@ -296,7 +296,7 @@ void BKE_previewimg_free(PreviewImage **prv)
{
if (prv && (*prv)) {
BKE_previewimg_freefunc(*prv);
- *prv = NULL;
+ *prv = nullptr;
}
}
@@ -321,7 +321,7 @@ void BKE_previewimg_clear(struct PreviewImage *prv)
PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
{
- PreviewImage *prv_img = NULL;
+ PreviewImage *prv_img = nullptr;
if (prv) {
prv_img = (PreviewImage *)MEM_dupallocN(prv);
@@ -329,7 +329,7 @@ PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
if (prv->rect[i]) {
prv_img->rect[i] = (uint *)MEM_dupallocN(prv->rect[i]);
}
- prv_img->gputexture[i] = NULL;
+ prv_img->gputexture[i] = nullptr;
}
}
return prv_img;
@@ -345,7 +345,7 @@ void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
if (old_prv_p && *old_prv_p) {
- BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p));
+ BLI_assert(new_prv_p != nullptr && ELEM(*new_prv_p, nullptr, *old_prv_p));
// const int new_icon_id = get_next_free_id();
// if (new_icon_id == 0) {
@@ -379,13 +379,13 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id)
break;
}
- return NULL;
+ return nullptr;
}
PreviewImage *BKE_previewimg_id_get(const ID *id)
{
PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
- return prv_p ? *prv_p : NULL;
+ return prv_p ? *prv_p : nullptr;
}
void BKE_previewimg_id_free(ID *id)
@@ -401,13 +401,13 @@ PreviewImage *BKE_previewimg_id_ensure(ID *id)
PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
if (prv_p) {
- if (*prv_p == NULL) {
+ if (*prv_p == nullptr) {
*prv_p = BKE_previewimg_create();
}
return *prv_p;
}
- return NULL;
+ return nullptr;
}
void BKE_previewimg_id_custom_set(ID *id, const char *path)
@@ -464,7 +464,7 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name)
{
BLI_assert(BLI_thread_is_main());
- PreviewImage *prv = NULL;
+ PreviewImage *prv = nullptr;
void **key_p, **prv_p;
if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) {
@@ -488,7 +488,7 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
{
BLI_assert(BLI_thread_is_main());
- PreviewImage *prv = NULL;
+ PreviewImage *prv = nullptr;
void **prv_p;
prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
@@ -599,7 +599,7 @@ ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
const unsigned int h = prv->h[size];
const unsigned int *rect = prv->rect[size];
- ImBuf *ima = NULL;
+ ImBuf *ima = nullptr;
if (w > 0 && h > 0 && rect) {
/* first allocate imbuf for copying preview into it */
@@ -627,7 +627,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
* but not doing so would causes all previews to be re-rendered after
* undo which is too expensive. */
- if (prv == NULL) {
+ if (prv == nullptr) {
return;
}
@@ -636,7 +636,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
if (!(U.flag & USER_SAVE_PREVIEWS)) {
prv_copy.w[1] = 0;
prv_copy.h[1] = 0;
- prv_copy.rect[1] = NULL;
+ prv_copy.rect[1] = nullptr;
}
BLO_write_struct_at_address(writer, PreviewImage, prv, &prv_copy);
if (prv_copy.rect[0]) {
@@ -649,7 +649,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
{
- if (prv == NULL) {
+ if (prv == nullptr) {
return;
}
@@ -657,7 +657,7 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
if (prv->rect[i]) {
BLO_read_data_address(reader, &prv->rect[i]);
}
- prv->gputexture[i] = NULL;
+ prv->gputexture[i] = nullptr;
/* For now consider previews read from file as finished to not confuse File Browser preview
* loading. That could be smarter and check if there's a preview job running instead.
* If the preview is tagged as changed, it needs to be updated anyway, so don't remove the tag.
@@ -676,7 +676,7 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
void BKE_icon_changed(const int icon_id)
{
- Icon *icon = NULL;
+ Icon *icon = nullptr;
if (!icon_id || G.background) {
return;
@@ -714,8 +714,8 @@ static Icon *icon_create(int icon_id, int obj_type, void *obj)
new_icon->flag = 0;
/* next two lines make sure image gets created */
- new_icon->drawinfo = NULL;
- new_icon->drawinfo_free = NULL;
+ new_icon->drawinfo = nullptr;
+ new_icon->drawinfo_free = nullptr;
{
std::scoped_lock lock(gIconMutex);
@@ -867,11 +867,11 @@ ImBuf *BKE_icon_imbuf_get_buffer(int icon_id)
Icon *icon = icon_ghash_lookup(icon_id);
if (!icon) {
CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
- return NULL;
+ return nullptr;
}
if (icon->obj_type != ICON_DATA_IMBUF) {
CLOG_ERROR(&LOG, "icon ID does not refer to an imbuf icon: %d", icon_id);
- return NULL;
+ return nullptr;
}
return (ImBuf *)icon->obj;
@@ -881,13 +881,13 @@ Icon *BKE_icon_get(const int icon_id)
{
BLI_assert(BLI_thread_is_main());
- Icon *icon = NULL;
+ Icon *icon = nullptr;
icon = icon_ghash_lookup(icon_id);
if (!icon) {
CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
- return NULL;
+ return nullptr;
}
return icon;
@@ -930,7 +930,7 @@ void BKE_icon_id_delete(struct ID *id)
BKE_icons_deferred_free();
std::scoped_lock lock(gIconMutex);
- BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), NULL, icon_free);
+ BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), nullptr, icon_free);
}
/**
@@ -944,7 +944,7 @@ bool BKE_icon_delete(const int icon_id)
}
std::scoped_lock lock(gIconMutex);
- if (Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL)) {
+ if (Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr)) {
icon_free_data(icon_id, icon);
icon_free(icon);
return true;
@@ -962,7 +962,7 @@ bool BKE_icon_delete_unmanaged(const int icon_id)
std::scoped_lock lock(gIconMutex);
- Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+ Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr);
if (icon) {
if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon);
@@ -1041,8 +1041,8 @@ struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
BLI_assert(BLI_thread_is_main());
size_t data_len;
uchar *data = (uchar *)BLI_file_read_binary_as_mem(filename, 0, &data_len);
- if (data == NULL) {
- return NULL;
+ if (data == nullptr) {
+ return nullptr;
}
return BKE_icon_geom_from_memory(data, data_len);
}
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c
index 9ed233ab34c..50138b34fa3 100644
--- a/source/blender/blenkernel/intern/image_gpu.c
+++ b/source/blender/blenkernel/intern/image_gpu.c
@@ -62,7 +62,7 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
return ibuf->rect_float != NULL;
}
}
- else if (ibuf) {
+ if (ibuf) {
if (ibuf->rect_float) {
return image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 8a699e31f37..fbad0d920ed 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -2054,7 +2054,7 @@ static void bke_view_layer_verify_aov_cb(void *userdata,
const char *name,
int UNUSED(channels),
const char *UNUSED(chanid),
- int UNUSED(type))
+ eNodeSocketDatatype UNUSED(type))
{
GHash *name_count = userdata;
void **value_p;
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index d82315a0e7f..cabc80d4024 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -369,6 +369,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
static bool lib_override_hierarchy_recursive_tag(Main *bmain,
ID *id,
const uint tag,
+ const uint missing_tag,
Library *override_group_lib_reference)
{
void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id);
@@ -377,9 +378,16 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
return (id->tag & tag) != 0;
}
+ /* Note: in case some reference ID is missing from linked data (and therefore its override uses
+ * a placeholder as reference), use `missing_tag` instead of `tag` for this override. */
if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
id->override_library->reference->lib == override_group_lib_reference) {
- id->tag |= tag;
+ if (id->override_library->reference->tag & LIB_TAG_MISSING) {
+ id->tag |= missing_tag;
+ }
+ else {
+ id->tag |= tag;
+ }
}
/* This way we won't process again that ID, should we encounter it again through another
@@ -397,7 +405,7 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
/* We only consider IDs from the same library. */
if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
if (lib_override_hierarchy_recursive_tag(
- bmain, *entry->id_pointer, tag, override_group_lib_reference) &&
+ bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) &&
override_group_lib_reference == NULL) {
id->tag |= tag;
}
@@ -430,7 +438,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain,
/* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shape-key
* has a driver using an armature object's bone, we need to override the shape-key/obdata,
* the objects using them, etc.) */
- lib_override_hierarchy_recursive_tag(bmain, id_root, tag, NULL);
+ lib_override_hierarchy_recursive_tag(bmain, id_root, tag, 0, NULL);
BKE_main_relations_free(bmain);
}
@@ -447,6 +455,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain,
void BKE_lib_override_library_override_group_tag(Main *bmain,
ID *id_root,
const uint tag,
+ const uint missing_tag,
const bool do_create_main_relashionships)
{
if (do_create_main_relashionships) {
@@ -456,7 +465,7 @@ void BKE_lib_override_library_override_group_tag(Main *bmain,
/* We tag all liboverride data-blocks from the same library as reference one,
* being used by the root ID. */
lib_override_hierarchy_recursive_tag(
- bmain, id_root, tag, id_root->override_library->reference->lib);
+ bmain, id_root, tag, missing_tag, id_root->override_library->reference->lib);
BKE_main_relations_free(bmain);
}
@@ -492,8 +501,9 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da
}
/* We tag all collections and objects for override. And we also tag all other data-blocks which
- * would use one of those. */
- if (ELEM(GS(id->name), ID_OB, ID_GR)) {
+ * would use one of those.
+ * Note: missing IDs (aka placeholders) are never overridden. */
+ if (ELEM(GS(id->name), ID_OB, ID_GR) && !(id->tag & LIB_TAG_MISSING)) {
id->tag |= LIB_TAG_DOIT;
}
@@ -692,6 +702,12 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
&ob_proxy->proxy->id;
ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
+ /* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not
+ * sure this is a valid state, but for now just abort the overriding process. */
+ if (!ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
+ return false;
+ }
+
/* We manually convert the proxy object into a library override, further override handling will
* then be handled by `BKE_lib_override_library_create()` just as for a regular override
* creation.
@@ -725,7 +741,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
/* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag
* linked reference ones to be overridden again. */
- BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true);
+ BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, true);
GHash *linkedref_to_old_override = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
@@ -835,6 +851,12 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
id->tag &= ~LIB_TAG_DOIT;
}
+ /* Also cleanup old overrides that went missing in new linked data. */
+ else if (id->tag & LIB_TAG_MISSING && !ID_IS_LINKED(id)) {
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY(id));
+ id->tag |= LIB_TAG_DOIT;
+ id->tag &= ~LIB_TAG_MISSING;
+ }
}
FOREACH_MAIN_ID_END;
BKE_id_multi_tagged_delete(bmain);
@@ -876,7 +898,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
id_root->tag |= LIB_TAG_DOIT;
/* Tag all library overrides in the chains of dependencies from the given root one. */
- BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true);
+ BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT, true);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc
new file mode 100644
index 00000000000..527288d06cf
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_fair.cc
@@ -0,0 +1,505 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing":
+ * https://github.com/fedackb/mesh-fairing.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_map.hh"
+#include "BLI_math.h"
+#include "BLI_vector.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_fair.h"
+#include "BKE_mesh_mapping.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "MEM_guardedalloc.h"
+#include "eigen_capi.h"
+
+using blender::Map;
+using blender::Vector;
+using std::array;
+
+class VertexWeight {
+ public:
+ virtual float weight_at_index(const int index) = 0;
+ virtual ~VertexWeight() = default;
+};
+
+class LoopWeight {
+ public:
+ virtual float weight_at_index(const int index) = 0;
+ virtual ~LoopWeight() = default;
+};
+
+class FairingContext {
+ public:
+ /* Get coordinates of vertices which are adjacent to the loop with specified index. */
+ virtual void adjacents_coords_from_loop(const int loop,
+ float r_adj_next[3],
+ float r_adj_prev[3]) = 0;
+
+ /* Get the other vertex index for a loop. */
+ virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) = 0;
+
+ int vertex_count_get()
+ {
+ return totvert_;
+ }
+
+ int loop_count_get()
+ {
+ return totvert_;
+ }
+
+ MeshElemMap *vertex_loop_map_get(const int v)
+ {
+ return &vlmap_[v];
+ }
+
+ float *vertex_deformation_co_get(const int v)
+ {
+ return co_[v];
+ }
+
+ virtual ~FairingContext() = default;
+
+ void fair_vertices(bool *affected,
+ const eMeshFairingDepth depth,
+ VertexWeight *vertex_weight,
+ LoopWeight *loop_weight)
+ {
+
+ fair_vertices_ex(affected, (int)depth, vertex_weight, loop_weight);
+ }
+
+ protected:
+ Vector<float *> co_;
+
+ int totvert_;
+ int totloop_;
+
+ MeshElemMap *vlmap_;
+ int *vlmap_mem_;
+
+ private:
+ void fair_setup_fairing(const int v,
+ const int i,
+ LinearSolver *solver,
+ float multiplier,
+ const int depth,
+ Map<int, int> &vert_col_map,
+ VertexWeight *vertex_weight,
+ LoopWeight *loop_weight)
+ {
+ if (depth == 0) {
+ if (vert_col_map.contains(v)) {
+ const int j = vert_col_map.lookup(v);
+ EIG_linear_solver_matrix_add(solver, i, j, -multiplier);
+ return;
+ }
+ for (int j = 0; j < 3; j++) {
+ EIG_linear_solver_right_hand_side_add(solver, j, i, multiplier * co_[v][j]);
+ }
+ return;
+ }
+
+ float w_ij_sum = 0;
+ const float w_i = vertex_weight->weight_at_index(v);
+ MeshElemMap *vlmap_elem = &vlmap_[v];
+ for (int l = 0; l < vlmap_elem->count; l++) {
+ const int l_index = vlmap_elem->indices[l];
+ const int other_vert = other_vertex_index_from_loop(l_index, v);
+ const float w_ij = loop_weight->weight_at_index(l_index);
+ w_ij_sum += w_ij;
+ fair_setup_fairing(other_vert,
+ i,
+ solver,
+ w_i * w_ij * multiplier,
+ depth - 1,
+ vert_col_map,
+ vertex_weight,
+ loop_weight);
+ }
+ fair_setup_fairing(v,
+ i,
+ solver,
+ -1 * w_i * w_ij_sum * multiplier,
+ depth - 1,
+ vert_col_map,
+ vertex_weight,
+ loop_weight);
+ }
+
+ void fair_vertices_ex(bool *affected,
+ const int order,
+ VertexWeight *vertex_weight,
+ LoopWeight *loop_weight)
+ {
+ Map<int, int> vert_col_map;
+ int num_affected_vertices = 0;
+ for (int i = 0; i < totvert_; i++) {
+ if (!affected[i]) {
+ continue;
+ }
+ vert_col_map.add(i, num_affected_vertices);
+ num_affected_vertices++;
+ }
+
+ /* Early return, nothing to do. */
+ if (num_affected_vertices == 0 || num_affected_vertices == totvert_) {
+ return;
+ }
+
+ /* Setup fairing matrices */
+ LinearSolver *solver = EIG_linear_solver_new(num_affected_vertices, num_affected_vertices, 3);
+ for (auto item : vert_col_map.items()) {
+ const int v = item.key;
+ const int col = item.value;
+ fair_setup_fairing(v, col, solver, 1.0f, order, vert_col_map, vertex_weight, loop_weight);
+ }
+
+ /* Solve linear system */
+ EIG_linear_solver_solve(solver);
+
+ /* Copy the result back to the mesh */
+ for (auto item : vert_col_map.items()) {
+ const int v = item.key;
+ const int col = item.value;
+ for (int j = 0; j < 3; j++) {
+ co_[v][j] = EIG_linear_solver_variable_get(solver, j, col);
+ }
+ }
+
+ /* Free solver data */
+ EIG_linear_solver_delete(solver);
+ }
+};
+
+class MeshFairingContext : public FairingContext {
+ public:
+ MeshFairingContext(Mesh *mesh, MVert *deform_mverts)
+ {
+ totvert_ = mesh->totvert;
+ totloop_ = mesh->totloop;
+
+ medge_ = mesh->medge;
+ mpoly_ = mesh->mpoly;
+ mloop_ = mesh->mloop;
+ BKE_mesh_vert_loop_map_create(&vlmap_,
+ &vlmap_mem_,
+ mesh->mpoly,
+ mesh->mloop,
+ mesh->totvert,
+ mesh->totpoly,
+ mesh->totloop);
+
+ /* Deformation coords. */
+ co_.reserve(mesh->totvert);
+ if (deform_mverts) {
+ for (int i = 0; i < mesh->totvert; i++) {
+ co_[i] = deform_mverts[i].co;
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totvert; i++) {
+ co_[i] = mesh->mvert[i].co;
+ }
+ }
+
+ loop_to_poly_map_.reserve(mesh->totloop);
+ for (int i = 0; i < mesh->totpoly; i++) {
+ for (int l = 0; l < mesh->mpoly[i].totloop; l++) {
+ loop_to_poly_map_[l + mesh->mpoly[i].loopstart] = i;
+ }
+ }
+ }
+
+ ~MeshFairingContext()
+ {
+ MEM_SAFE_FREE(vlmap_);
+ MEM_SAFE_FREE(vlmap_mem_);
+ }
+
+ virtual void adjacents_coords_from_loop(const int loop,
+ float r_adj_next[3],
+ float r_adj_prev[3]) override
+ {
+ const int vert = mloop_[loop].v;
+ const MPoly *p = &mpoly_[loop_to_poly_map_[loop]];
+ const int corner = poly_find_loop_from_vert(p, &mloop_[p->loopstart], vert);
+ copy_v3_v3(r_adj_next, co_[ME_POLY_LOOP_NEXT(mloop_, p, corner)->v]);
+ copy_v3_v3(r_adj_prev, co_[ME_POLY_LOOP_PREV(mloop_, p, corner)->v]);
+ }
+
+ virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) override
+ {
+ MEdge *e = &medge_[mloop_[loop].e];
+ if (e->v1 == v) {
+ return e->v2;
+ }
+ return e->v1;
+ }
+
+ protected:
+ Mesh *mesh_;
+ MLoop *mloop_;
+ MPoly *mpoly_;
+ MEdge *medge_;
+ Vector<int> loop_to_poly_map_;
+};
+
+class BMeshFairingContext : public FairingContext {
+ public:
+ BMeshFairingContext(BMesh *bm)
+ {
+ this->bm = bm;
+ totvert_ = bm->totvert;
+ totloop_ = bm->totloop;
+
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ /* Deformation coords. */
+ co_.reserve(bm->totvert);
+ for (int i = 0; i < bm->totvert; i++) {
+ BMVert *v = BM_vert_at_index(bm, i);
+ co_[i] = v->co;
+ }
+
+ bmloop_.reserve(bm->totloop);
+ vlmap_ = (MeshElemMap *)MEM_calloc_arrayN(sizeof(MeshElemMap), bm->totvert, "bmesh loop map");
+ vlmap_mem_ = (int *)MEM_malloc_arrayN(sizeof(int), bm->totloop, "bmesh loop map mempool");
+
+ BMVert *v;
+ BMLoop *l;
+ BMIter iter;
+ BMIter loop_iter;
+ int index_iter = 0;
+
+ /* This initializes both the bmloop and the vlmap for bmesh in a single loop. */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ int loop_count = 0;
+ const int vert_index = BM_elem_index_get(v);
+ vlmap_[vert_index].indices = &vlmap_mem_[index_iter];
+ BM_ITER_ELEM (l, &loop_iter, v, BM_LOOPS_OF_VERT) {
+ const int loop_index = BM_elem_index_get(l);
+ bmloop_[loop_index] = l;
+ vlmap_mem_[index_iter] = loop_index;
+ index_iter++;
+ loop_count++;
+ }
+ vlmap_[vert_index].count = loop_count;
+ }
+ }
+
+ ~BMeshFairingContext()
+ {
+ MEM_SAFE_FREE(vlmap_);
+ MEM_SAFE_FREE(vlmap_mem_);
+ }
+
+ virtual void adjacents_coords_from_loop(const int loop,
+ float r_adj_next[3],
+ float r_adj_prev[3]) override
+ {
+ copy_v3_v3(r_adj_next, bmloop_[loop]->next->v->co);
+ copy_v3_v3(r_adj_prev, bmloop_[loop]->prev->v->co);
+ }
+
+ virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) override
+ {
+ BMLoop *l = bmloop_[loop];
+ BMVert *bmvert = BM_vert_at_index(bm, v);
+ BMVert *bm_other_vert = BM_edge_other_vert(l->e, bmvert);
+ return BM_elem_index_get(bm_other_vert);
+ }
+
+ protected:
+ BMesh *bm;
+ Vector<BMLoop *> bmloop_;
+};
+
+class UniformVertexWeight : public VertexWeight {
+ public:
+ UniformVertexWeight(FairingContext *fairing_context)
+ {
+ const int totvert = fairing_context->vertex_count_get();
+ vertex_weights_.reserve(totvert);
+ for (int i = 0; i < totvert; i++) {
+ const int tot_loop = fairing_context->vertex_loop_map_get(i)->count;
+ if (tot_loop != 0) {
+ vertex_weights_[i] = 1.0f / tot_loop;
+ }
+ else {
+ vertex_weights_[i] = FLT_MAX;
+ }
+ }
+ }
+ ~UniformVertexWeight() = default;
+
+ float weight_at_index(const int index) override
+ {
+ return vertex_weights_[index];
+ }
+
+ private:
+ Vector<float> vertex_weights_;
+};
+
+class VoronoiVertexWeight : public VertexWeight {
+
+ public:
+ VoronoiVertexWeight(FairingContext *fairing_context)
+ {
+
+ const int totvert = fairing_context->vertex_count_get();
+ vertex_weights_.reserve(totvert);
+ for (int i = 0; i < totvert; i++) {
+
+ float area = 0.0f;
+ float a[3];
+ copy_v3_v3(a, fairing_context->vertex_deformation_co_get(i));
+ const float acute_threshold = M_PI_2;
+
+ MeshElemMap *vlmap_elem = fairing_context->vertex_loop_map_get(i);
+ for (int l = 0; l < vlmap_elem->count; l++) {
+ const int l_index = vlmap_elem->indices[l];
+
+ float b[3], c[3], d[3];
+ fairing_context->adjacents_coords_from_loop(l_index, b, c);
+
+ if (angle_v3v3v3(c, fairing_context->vertex_deformation_co_get(i), b) < acute_threshold) {
+ calc_circumcenter(d, a, b, c);
+ }
+ else {
+ add_v3_v3v3(d, b, c);
+ mul_v3_fl(d, 0.5f);
+ }
+
+ float t[3];
+ add_v3_v3v3(t, a, b);
+ mul_v3_fl(t, 0.5f);
+ area += area_tri_v3(a, t, d);
+
+ add_v3_v3v3(t, a, c);
+ mul_v3_fl(t, 0.5f);
+ area += area_tri_v3(a, d, t);
+ }
+
+ vertex_weights_[i] = area != 0.0f ? 1.0f / area : 1e12;
+ }
+ }
+ ~VoronoiVertexWeight() = default;
+
+ float weight_at_index(const int index) override
+ {
+ return vertex_weights_[index];
+ }
+
+ private:
+ Vector<float> vertex_weights_;
+
+ void calc_circumcenter(float r[3], const float a[3], const float b[3], const float c[3])
+ {
+ float ab[3];
+ sub_v3_v3v3(ab, b, a);
+
+ float ac[3];
+ sub_v3_v3v3(ac, c, a);
+
+ float ab_cross_ac[3];
+ cross_v3_v3v3(ab_cross_ac, ab, ac);
+
+ if (len_squared_v3(ab_cross_ac) > 0.0f) {
+ float d[3];
+ cross_v3_v3v3(d, ab_cross_ac, ab);
+ mul_v3_fl(d, len_squared_v3(ac));
+
+ float t[3];
+ cross_v3_v3v3(t, ac, ab_cross_ac);
+ mul_v3_fl(t, len_squared_v3(ab));
+
+ add_v3_v3(d, t);
+
+ mul_v3_fl(d, 1.0f / (2.0f * len_squared_v3(ab_cross_ac)));
+
+ add_v3_v3v3(r, a, d);
+ return;
+ }
+ copy_v3_v3(r, a);
+ }
+};
+
+class UniformLoopWeight : public LoopWeight {
+ public:
+ float weight_at_index(const int UNUSED(index)) override
+ {
+ return 1.0f;
+ }
+};
+
+static void prefair_and_fair_vertices(FairingContext *fairing_context,
+ bool *affected_vertices,
+ const eMeshFairingDepth depth)
+{
+ /* Prefair. */
+ UniformVertexWeight *uniform_vertex_weights = new UniformVertexWeight(fairing_context);
+ UniformLoopWeight *uniform_loop_weights = new UniformLoopWeight();
+ fairing_context->fair_vertices(
+ affected_vertices, depth, uniform_vertex_weights, uniform_loop_weights);
+ delete uniform_vertex_weights;
+
+ /* Fair. */
+ VoronoiVertexWeight *voronoi_vertex_weights = new VoronoiVertexWeight(fairing_context);
+ /* TODO: Implemente cotangent loop weights. */
+ fairing_context->fair_vertices(
+ affected_vertices, depth, voronoi_vertex_weights, uniform_loop_weights);
+
+ delete uniform_loop_weights;
+ delete voronoi_vertex_weights;
+}
+
+void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh,
+ struct MVert *deform_mverts,
+ bool *affect_vertices,
+ const eMeshFairingDepth depth)
+{
+ MeshFairingContext *fairing_context = new MeshFairingContext(mesh, deform_mverts);
+ prefair_and_fair_vertices(fairing_context, affect_vertices, depth);
+ delete fairing_context;
+}
+
+void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm,
+ bool *affect_vertices,
+ const eMeshFairingDepth depth)
+{
+ BMeshFairingContext *fairing_context = new BMeshFairingContext(bm);
+ prefair_and_fair_vertices(fairing_context, affect_vertices, depth);
+ delete fairing_context;
+}
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h
index 39c6da0b6c8..0a03387282f 100644
--- a/source/blender/blenkernel/intern/multires_unsubdivide.h
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.h
@@ -26,10 +26,8 @@
#include "BLI_sys_types.h"
struct BMesh;
-struct Depsgraph;
struct Mesh;
struct MultiresModifierData;
-struct Object;
typedef struct MultiresUnsubdivideGrid {
/* For sanity checks. */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 87997198334..415eb14be66 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -4737,10 +4737,11 @@ static void registerGeometryNodes(void)
register_node_type_geo_point_distribute();
register_node_type_geo_point_instance();
register_node_type_geo_object_info();
- register_node_type_geo_random_attribute();
+ register_node_type_geo_attribute_randomize();
register_node_type_geo_attribute_math();
register_node_type_geo_join_geometry();
register_node_type_geo_attribute_mix();
+ register_node_type_geo_attribute_color_ramp();
}
static void registerFunctionNodes(void)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index f63d443d29f..cc192c1c3c0 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -222,6 +222,7 @@ static void scene_init_data(ID *id)
/* Curve Profile */
scene->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
+ scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init();
for (size_t i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) {
scene->orientation_slots[i].index_custom = -1;
@@ -862,6 +863,9 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
if (tos->custom_bevel_profile_preset) {
BKE_curveprofile_blend_write(writer, tos->custom_bevel_profile_preset);
}
+ if (tos->sequencer_tool_settings) {
+ BLO_write_struct(writer, SequencerToolSettings, tos->sequencer_tool_settings);
+ }
BKE_paint_blend_write(writer, &tos->imapaint.paint);
@@ -1121,6 +1125,8 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
if (sce->toolsettings->custom_bevel_profile_preset) {
BKE_curveprofile_blend_read(reader, sce->toolsettings->custom_bevel_profile_preset);
}
+
+ BLO_read_data_address(reader, &sce->toolsettings->sequencer_tool_settings);
}
if (sce->ed) {
@@ -1792,6 +1798,8 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->gp_sculpt.cur_primitive = BKE_curvemapping_copy(ts->gp_sculpt.cur_primitive);
ts->custom_bevel_profile_preset = BKE_curveprofile_copy(ts->custom_bevel_profile_preset);
+
+ ts->sequencer_tool_settings = SEQ_tool_settings_copy(ts->sequencer_tool_settings);
return ts;
}
@@ -1850,6 +1858,10 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_curveprofile_free(toolsettings->custom_bevel_profile_preset);
}
+ if (toolsettings->sequencer_tool_settings) {
+ SEQ_tool_settings_free(toolsettings->sequencer_tool_settings);
+ }
+
MEM_freeN(toolsettings);
}
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index 8a7dcb7ffaa..284d62fb876 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -220,13 +220,13 @@ class Array {
return MutableSpan<T>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator Span<U>() const
{
return Span<U>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator MutableSpan<U>()
{
return MutableSpan<U>(data_, size_);
diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh
index 2b060c986cd..4121542c887 100644
--- a/source/blender/blenlib/BLI_index_range.hh
+++ b/source/blender/blenlib/BLI_index_range.hh
@@ -73,21 +73,22 @@ class IndexRange {
int64_t size_ = 0;
public:
- IndexRange() = default;
+ constexpr IndexRange() = default;
- explicit IndexRange(int64_t size) : start_(0), size_(size)
+ constexpr explicit IndexRange(int64_t size) : start_(0), size_(size)
{
BLI_assert(size >= 0);
}
- IndexRange(int64_t start, int64_t size) : start_(start), size_(size)
+ constexpr IndexRange(int64_t start, int64_t size) : start_(start), size_(size)
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
}
template<typename T>
- IndexRange(const tbb::blocked_range<T> &range) : start_(range.begin()), size_(range.size())
+ constexpr IndexRange(const tbb::blocked_range<T> &range)
+ : start_(range.begin()), size_(range.size())
{
}
@@ -96,33 +97,33 @@ class IndexRange {
int64_t current_;
public:
- Iterator(int64_t current) : current_(current)
+ constexpr Iterator(int64_t current) : current_(current)
{
}
- Iterator &operator++()
+ constexpr Iterator &operator++()
{
current_++;
return *this;
}
- bool operator!=(const Iterator &iterator) const
+ constexpr bool operator!=(const Iterator &iterator) const
{
return current_ != iterator.current_;
}
- int64_t operator*() const
+ constexpr int64_t operator*() const
{
return current_;
}
};
- Iterator begin() const
+ constexpr Iterator begin() const
{
return Iterator(start_);
}
- Iterator end() const
+ constexpr Iterator end() const
{
return Iterator(start_ + size_);
}
@@ -130,7 +131,7 @@ class IndexRange {
/**
* Access an element in the range.
*/
- int64_t operator[](int64_t index) const
+ constexpr int64_t operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
@@ -140,7 +141,7 @@ class IndexRange {
/**
* Two ranges compare equal when they contain the same numbers.
*/
- friend bool operator==(IndexRange a, IndexRange b)
+ constexpr friend bool operator==(IndexRange a, IndexRange b)
{
return (a.size_ == b.size_) && (a.start_ == b.start_ || a.size_ == 0);
}
@@ -148,7 +149,7 @@ class IndexRange {
/**
* Get the amount of numbers in the range.
*/
- int64_t size() const
+ constexpr int64_t size() const
{
return size_;
}
@@ -156,7 +157,7 @@ class IndexRange {
/**
* Create a new range starting at the end of the current one.
*/
- IndexRange after(int64_t n) const
+ constexpr IndexRange after(int64_t n) const
{
BLI_assert(n >= 0);
return IndexRange(start_ + size_, n);
@@ -165,7 +166,7 @@ class IndexRange {
/**
* Create a new range that ends at the start of the current one.
*/
- IndexRange before(int64_t n) const
+ constexpr IndexRange before(int64_t n) const
{
BLI_assert(n >= 0);
return IndexRange(start_ - n, n);
@@ -175,7 +176,7 @@ class IndexRange {
* Get the first element in the range.
* Asserts when the range is empty.
*/
- int64_t first() const
+ constexpr int64_t first() const
{
BLI_assert(this->size() > 0);
return start_;
@@ -185,7 +186,7 @@ class IndexRange {
* Get the last element in the range.
* Asserts when the range is empty.
*/
- int64_t last() const
+ constexpr int64_t last() const
{
BLI_assert(this->size() > 0);
return start_ + size_ - 1;
@@ -194,7 +195,7 @@ class IndexRange {
/**
* Get the element one after the end. The returned value is undefined when the range is empty.
*/
- int64_t one_after_last() const
+ constexpr int64_t one_after_last() const
{
return start_ + size_;
}
@@ -202,7 +203,7 @@ class IndexRange {
/**
* Get the first element in the range. The returned value is undefined when the range is empty.
*/
- int64_t start() const
+ constexpr int64_t start() const
{
return start_;
}
@@ -210,7 +211,7 @@ class IndexRange {
/**
* Returns true when the range contains a certain number, otherwise false.
*/
- bool contains(int64_t value) const
+ constexpr bool contains(int64_t value) const
{
return value >= start_ && value < start_ + size_;
}
@@ -218,7 +219,7 @@ class IndexRange {
/**
* Returns a new range, that contains a sub-interval of the current one.
*/
- IndexRange slice(int64_t start, int64_t size) const
+ constexpr IndexRange slice(int64_t start, int64_t size) const
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
@@ -226,7 +227,7 @@ class IndexRange {
BLI_assert(new_start + size <= start_ + size_ || size == 0);
return IndexRange(new_start, size);
}
- IndexRange slice(IndexRange range) const
+ constexpr IndexRange slice(IndexRange range) const
{
return this->slice(range.start(), range.size());
}
diff --git a/source/blender/blenlib/BLI_inplace_priority_queue.hh b/source/blender/blenlib/BLI_inplace_priority_queue.hh
new file mode 100644
index 00000000000..e76cb8504a3
--- /dev/null
+++ b/source/blender/blenlib/BLI_inplace_priority_queue.hh
@@ -0,0 +1,304 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BLI_array.hh"
+#include "BLI_dot_export.hh"
+
+namespace blender {
+
+/**
+ * An InplacePriorityQueue adds priority queue functionality to an existing array. The underlying
+ * array is not changed. Instead, the priority queue maintains indices into the original array.
+ *
+ * The priority queue provides efficient access to the element in order of their priorities.
+ *
+ * When a priority changes, the priority queue has to be informed using one of the following
+ * methods: #priority_decreased, #priority_increased or #priority_changed.
+ */
+template<
+ /* Type of the elements in the underlying array. */
+ typename T,
+ /* Binary function that takes two `const T &` inputs and returns true, when the first input has
+ greater priority than the second. */
+ typename FirstHasHigherPriority = std::greater<T>>
+class InplacePriorityQueue {
+ private:
+ /* Underlying array the priority queue is built upon. This is a span instead of a mutable span,
+ * because this data structure never changes the values itself. */
+ Span<T> data_;
+ /* Maps indices from the heap (binary tree in array format) to indices of the underlying/original
+ * array. */
+ Array<int64_t> heap_to_orig_;
+ /* This is the inversion of the above mapping. */
+ Array<int64_t> orig_to_heap_;
+ /* Number of elements that are currently in the priority queue. */
+ int64_t heap_size_ = 0;
+ /* Function that can be changed to customize how the priority of two elements is compared. */
+ FirstHasHigherPriority first_has_higher_priority_fn_;
+
+ public:
+ /**
+ * Construct the priority queue on top of the data in the given span.
+ */
+ InplacePriorityQueue(Span<T> data)
+ : data_(data), heap_to_orig_(data_.size()), orig_to_heap_(data_.size())
+ {
+ for (const int64_t i : IndexRange(data_.size())) {
+ heap_to_orig_[i] = i;
+ orig_to_heap_[i] = i;
+ }
+
+ this->rebuild();
+ }
+
+ /**
+ * Rebuilds the priority queue from the array that has been passed to the constructor.
+ */
+ void rebuild()
+ {
+ const int final_heap_size = data_.size();
+ if (final_heap_size > 1) {
+ for (int64_t i = this->get_parent(final_heap_size - 1); i >= 0; i--) {
+ this->heapify(i, final_heap_size);
+ }
+ }
+ heap_size_ = final_heap_size;
+ }
+
+ /**
+ * Returns the number of elements in the priority queue.
+ * This is less or equal than the size of the underlying array.
+ */
+ int64_t size() const
+ {
+ return heap_size_;
+ }
+
+ /**
+ * Returns true, when the priority queue contains no elements. If this returns true, #peek and
+ * #pop must not be used.
+ */
+ bool is_empty() const
+ {
+ return heap_size_ == 0;
+ }
+
+ /**
+ * Get the element with the highest priority in the priority queue.
+ * The returned reference is const, because the priority queue has read-only access to the
+ * underlying data. If you need a mutable reference, use #peek_index instead.
+ */
+ const T &peek() const
+ {
+ return data_[this->peek_index()];
+ }
+
+ /**
+ * Get the element with the highest priority in the priority queue and remove it.
+ * The returned reference is const, because the priority queue has read-only access to the
+ * underlying data. If you need a mutable reference, use #pop_index instead.
+ */
+ const T &pop()
+ {
+ return data_[this->pop_index()];
+ }
+
+ /**
+ * Get the index of the element with the highest priority in the priority queue.
+ */
+ int64_t peek_index() const
+ {
+ BLI_assert(!this->is_empty());
+ return heap_to_orig_[0];
+ }
+
+ /**
+ * Get the index of the element with the highest priority in the priority queue and remove it.
+ */
+ int64_t pop_index()
+ {
+ BLI_assert(!this->is_empty());
+ const int64_t top_index_orig = heap_to_orig_[0];
+ heap_size_--;
+ if (heap_size_ > 1) {
+ this->swap_indices(0, heap_size_);
+ this->heapify(0, heap_size_);
+ }
+ return top_index_orig;
+ }
+
+ /**
+ * Inform the priority queue that the priority of the element at the given index has been
+ * decreased.
+ */
+ void priority_decreased(const int64_t index)
+ {
+ const int64_t heap_index = orig_to_heap_[index];
+ if (heap_index >= heap_size_) {
+ /* This element is not in the queue currently. */
+ return;
+ }
+ this->heapify(heap_index, heap_size_);
+ }
+
+ /**
+ * Inform the priority queue that the priority of the element at the given index has been
+ * increased.
+ */
+ void priority_increased(const int64_t index)
+ {
+ int64_t current = orig_to_heap_[index];
+ if (current >= heap_size_) {
+ /* This element is not in the queue currently. */
+ return;
+ }
+ while (true) {
+ if (current == 0) {
+ break;
+ }
+ const int64_t parent = this->get_parent(current);
+ if (this->first_has_higher_priority(parent, current)) {
+ break;
+ }
+ this->swap_indices(current, parent);
+ current = parent;
+ }
+ }
+
+ /**
+ * Inform the priority queue that the priority of the element at the given index has been
+ * changed.
+ */
+ void priority_changed(const int64_t index)
+ {
+ this->priority_increased(index);
+ this->priority_decreased(index);
+ }
+
+ /**
+ * Returns the indices of all elements that are in the priority queue.
+ * There are no guarantees about the order of indices.
+ */
+ Span<int64_t> active_indices() const
+ {
+ return heap_to_orig_.as_span().take_front(heap_size_);
+ }
+
+ /**
+ * Returns the indices of all elements that are not in the priority queue.
+ * The indices are in reverse order of their removal from the queue.
+ * I.e. the index that has been removed last, comes first.
+ */
+ Span<int64_t> inactive_indices() const
+ {
+ return heap_to_orig_.as_span().drop_front(heap_size_);
+ }
+
+ /**
+ * Returns the concatenation of the active and inactive indices.
+ */
+ Span<int64_t> all_indices() const
+ {
+ return heap_to_orig_;
+ }
+
+ /**
+ * Return the heap used by the priority queue as dot graph string.
+ * This exists for debugging purposes.
+ */
+ std::string to_dot() const
+ {
+ return this->partial_to_dot(heap_size_);
+ }
+
+ private:
+ bool first_has_higher_priority(const int64_t a, const int64_t b)
+ {
+ const T &value_a = data_[heap_to_orig_[a]];
+ const T &value_b = data_[heap_to_orig_[b]];
+ return first_has_higher_priority_fn_(value_a, value_b);
+ }
+
+ void swap_indices(const int64_t a, const int64_t b)
+ {
+ std::swap(heap_to_orig_[a], heap_to_orig_[b]);
+ orig_to_heap_[heap_to_orig_[a]] = a;
+ orig_to_heap_[heap_to_orig_[b]] = b;
+ }
+
+ void heapify(const int64_t parent, const int64_t heap_size)
+ {
+ int64_t max_index = parent;
+ const int left = this->get_left(parent);
+ const int right = this->get_right(parent);
+ if (left < heap_size && this->first_has_higher_priority(left, max_index)) {
+ max_index = left;
+ }
+ if (right < heap_size && this->first_has_higher_priority(right, max_index)) {
+ max_index = right;
+ }
+ if (max_index != parent) {
+ this->swap_indices(parent, max_index);
+ this->heapify(max_index, heap_size);
+ }
+ if (left < heap_size) {
+ BLI_assert(!this->first_has_higher_priority(left, parent));
+ }
+ if (right < heap_size) {
+ BLI_assert(!this->first_has_higher_priority(right, parent));
+ }
+ }
+
+ int64_t get_parent(const int64_t child) const
+ {
+ BLI_assert(child > 0);
+ return (child - 1) / 2;
+ }
+
+ int64_t get_left(const int64_t parent) const
+ {
+ return parent * 2 + 1;
+ }
+
+ int64_t get_right(const int64_t parent) const
+ {
+ return parent * 2 + 2;
+ }
+
+ std::string partial_to_dot(const int size) const
+ {
+ dot::DirectedGraph digraph;
+ Array<dot::Node *> dot_nodes(size);
+ for (const int i : IndexRange(size)) {
+ std::stringstream ss;
+ ss << data_[heap_to_orig_[i]];
+ const std::string name = ss.str();
+ dot::Node &node = digraph.new_node(name);
+ node.set_shape(dot::Attr_shape::Rectangle);
+ node.attributes.set("ordering", "out");
+ dot_nodes[i] = &node;
+ if (i > 0) {
+ const int64_t parent = this->get_parent(i);
+ digraph.new_edge(*dot_nodes[parent], node);
+ }
+ }
+ return digraph.to_dot_string();
+ }
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index c34b71a60f9..5e0ea4f2a99 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -178,6 +178,7 @@ int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersec
int BLI_bvhtree_get_len(const BVHTree *tree);
int BLI_bvhtree_get_tree_type(const BVHTree *tree);
float BLI_bvhtree_get_epsilon(const BVHTree *tree);
+void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]);
/* find nearest node to the given coordinates
* (if nearest is given it will only search nodes where
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index 49076bb1aae..b3b6855089e 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -428,6 +428,25 @@ inline constexpr bool is_convertible_pointer_v =
std::is_convertible_v<From, To> &&std::is_pointer_v<From> &&std::is_pointer_v<To>;
/**
+ * Helper variable that checks if a Span<From> can be converted to Span<To> safely, whereby From
+ * and To are pointers. Adding const and casting to a void pointer is allowed.
+ * Casting up and down a class hierarchy generally is not allowed, because this might change the
+ * pointer under some circumstances.
+ */
+template<typename From, typename To>
+inline constexpr bool is_span_convertible_pointer_v =
+ /* Make sure we are working with pointers. */
+ std::is_pointer_v<From> &&std::is_pointer_v<To> &&
+ (/* No casting is necessary when both types are the same. */
+ std::is_same_v<From, To> ||
+ /* Allow adding const to the underlying type. */
+ std::is_same_v<const std::remove_pointer_t<From>, std::remove_pointer_t<To>> ||
+ /* Allow casting non-const pointers to void pointers. */
+ (!std::is_const_v<std::remove_pointer_t<From>> && std::is_same_v<To, void *>) ||
+ /* Allow casting any pointer to const void pointers. */
+ std::is_same_v<To, const void *>);
+
+/**
* Inline buffers for small-object-optimization should be disable by default. Otherwise we might
* get large unexpected allocations on the stack.
*/
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 5b4d2769f57..8011b2f9abc 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -93,15 +93,15 @@ template<typename T> class Span {
/**
* Create a reference to an empty array.
*/
- Span() = default;
+ constexpr Span() = default;
- Span(const T *start, int64_t size) : data_(start), size_(size)
+ constexpr Span(const T *start, int64_t size) : data_(start), size_(size)
{
BLI_assert(size >= 0);
}
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
- Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size)
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ constexpr Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size)
{
BLI_assert(size >= 0);
}
@@ -117,16 +117,17 @@ template<typename T> class Span {
* Span<int> span = {1, 2, 3, 4};
* call_function_with_array(span);
*/
- Span(const std::initializer_list<T> &list)
+ constexpr Span(const std::initializer_list<T> &list)
: Span(list.begin(), static_cast<int64_t>(list.size()))
{
}
- Span(const std::vector<T> &vector) : Span(vector.data(), static_cast<int64_t>(vector.size()))
+ constexpr Span(const std::vector<T> &vector)
+ : Span(vector.data(), static_cast<int64_t>(vector.size()))
{
}
- template<std::size_t N> Span(const std::array<T, N> &array) : Span(array.data(), N)
+ template<std::size_t N> constexpr Span(const std::array<T, N> &array) : Span(array.data(), N)
{
}
@@ -134,8 +135,9 @@ template<typename T> class Span {
* Support implicit conversions like the ones below:
* Span<T *> -> Span<const T *>
*/
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
- Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size())
+
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ constexpr Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size())
{
}
@@ -143,7 +145,7 @@ template<typename T> class Span {
* Returns a contiguous part of the array. This invokes undefined behavior when the slice does
* not stay within the bounds of the array.
*/
- Span slice(int64_t start, int64_t size) const
+ constexpr Span slice(int64_t start, int64_t size) const
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
@@ -151,7 +153,7 @@ template<typename T> class Span {
return Span(data_ + start, size);
}
- Span slice(IndexRange range) const
+ constexpr Span slice(IndexRange range) const
{
return this->slice(range.start(), range.size());
}
@@ -160,7 +162,7 @@ template<typename T> class Span {
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when the array is too small.
*/
- Span drop_front(int64_t n) const
+ constexpr Span drop_front(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@@ -171,7 +173,7 @@ template<typename T> class Span {
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when the array is too small.
*/
- Span drop_back(int64_t n) const
+ constexpr Span drop_back(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@@ -182,7 +184,7 @@ template<typename T> class Span {
* Returns a new Span that only contains the first n elements. This invokes undefined
* behavior when the array is too small.
*/
- Span take_front(int64_t n) const
+ constexpr Span take_front(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@@ -193,7 +195,7 @@ template<typename T> class Span {
* Returns a new Span that only contains the last n elements. This invokes undefined
* behavior when the array is too small.
*/
- Span take_back(int64_t n) const
+ constexpr Span take_back(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@@ -204,25 +206,25 @@ template<typename T> class Span {
* Returns the pointer to the beginning of the referenced array. This may be nullptr when the
* size is zero.
*/
- const T *data() const
+ constexpr const T *data() const
{
return data_;
}
- const T *begin() const
+ constexpr const T *begin() const
{
return data_;
}
- const T *end() const
+ constexpr const T *end() const
{
return data_ + size_;
}
- std::reverse_iterator<const T *> rbegin() const
+ constexpr std::reverse_iterator<const T *> rbegin() const
{
return std::reverse_iterator<const T *>(this->end());
}
- std::reverse_iterator<const T *> rend() const
+ constexpr std::reverse_iterator<const T *> rend() const
{
return std::reverse_iterator<const T *>(this->begin());
}
@@ -231,7 +233,7 @@ template<typename T> class Span {
* Access an element in the array. This invokes undefined behavior when the index is out of
* bounds.
*/
- const T &operator[](int64_t index) const
+ constexpr const T &operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
@@ -241,7 +243,7 @@ template<typename T> class Span {
/**
* Returns the number of elements in the referenced array.
*/
- int64_t size() const
+ constexpr int64_t size() const
{
return size_;
}
@@ -249,7 +251,7 @@ template<typename T> class Span {
/**
* Returns true if the size is zero.
*/
- bool is_empty() const
+ constexpr bool is_empty() const
{
return size_ == 0;
}
@@ -257,7 +259,7 @@ template<typename T> class Span {
/**
* Returns the number of bytes referenced by this Span.
*/
- int64_t size_in_bytes() const
+ constexpr int64_t size_in_bytes() const
{
return sizeof(T) * size_;
}
@@ -266,7 +268,7 @@ template<typename T> class Span {
* Does a linear search to see of the value is in the array.
* Returns true if it is, otherwise false.
*/
- bool contains(const T &value) const
+ constexpr bool contains(const T &value) const
{
for (const T &element : *this) {
if (element == value) {
@@ -280,7 +282,7 @@ template<typename T> class Span {
* Does a constant time check to see if the pointer points to a value in the referenced array.
* Return true if it is, otherwise false.
*/
- bool contains_ptr(const T *ptr) const
+ constexpr bool contains_ptr(const T *ptr) const
{
return (this->begin() <= ptr) && (ptr < this->end());
}
@@ -289,7 +291,7 @@ template<typename T> class Span {
* Does a linear search to count how often the value is in the array.
* Returns the number of occurrences.
*/
- int64_t count(const T &value) const
+ constexpr int64_t count(const T &value) const
{
int64_t counter = 0;
for (const T &element : *this) {
@@ -304,7 +306,7 @@ template<typename T> class Span {
* Return a reference to the first element in the array. This invokes undefined behavior when the
* array is empty.
*/
- const T &first() const
+ constexpr const T &first() const
{
BLI_assert(size_ > 0);
return data_[0];
@@ -314,7 +316,7 @@ template<typename T> class Span {
* Returns a reference to the last element in the array. This invokes undefined behavior when the
* array is empty.
*/
- const T &last() const
+ constexpr const T &last() const
{
BLI_assert(size_ > 0);
return data_[size_ - 1];
@@ -324,7 +326,7 @@ template<typename T> class Span {
* Returns the element at the given index. If the index is out of range, return the fallback
* value.
*/
- T get(int64_t index, const T &fallback) const
+ constexpr T get(int64_t index, const T &fallback) const
{
if (index < size_ && index >= 0) {
return data_[index];
@@ -336,7 +338,7 @@ template<typename T> class Span {
* Check if the array contains duplicates. Does a linear search for every element. So the total
* running time is O(n^2). Only use this for small arrays.
*/
- bool has_duplicates__linear_search() const
+ constexpr bool has_duplicates__linear_search() const
{
/* The size should really be smaller than that. If it is not, the calling code should be
* changed. */
@@ -358,7 +360,7 @@ template<typename T> class Span {
* called on small arrays, because it has a running time of O(n*m) where n and m are the sizes of
* the arrays.
*/
- bool intersects__linear_search(Span other) const
+ constexpr bool intersects__linear_search(Span other) const
{
/* The size should really be smaller than that. If it is not, the calling code should be
* changed. */
@@ -377,7 +379,7 @@ template<typename T> class Span {
* Returns the index of the first occurrence of the given value. This invokes undefined behavior
* when the value is not in the array.
*/
- int64_t first_index(const T &search_value) const
+ constexpr int64_t first_index(const T &search_value) const
{
const int64_t index = this->first_index_try(search_value);
BLI_assert(index >= 0);
@@ -387,7 +389,7 @@ template<typename T> class Span {
/**
* Returns the index of the first occurrence of the given value or -1 if it does not exist.
*/
- int64_t first_index_try(const T &search_value) const
+ constexpr int64_t first_index_try(const T &search_value) const
{
for (int64_t i = 0; i < size_; i++) {
if (data_[i] == search_value) {
@@ -401,7 +403,7 @@ template<typename T> class Span {
* Utility to make it more convenient to iterate over all indices that can be used with this
* array.
*/
- IndexRange index_range() const
+ constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@@ -409,7 +411,7 @@ template<typename T> class Span {
/**
* Returns a new Span to the same underlying memory buffer. No conversions are done.
*/
- template<typename NewT> Span<NewT> cast() const
+ template<typename NewT> Span<NewT> constexpr cast() const
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
@@ -450,21 +452,22 @@ template<typename T> class MutableSpan {
int64_t size_;
public:
- MutableSpan() = default;
+ constexpr MutableSpan() = default;
- MutableSpan(T *start, const int64_t size) : data_(start), size_(size)
+ constexpr MutableSpan(T *start, const int64_t size) : data_(start), size_(size)
{
}
- MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size())
+ constexpr MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size())
{
}
- template<std::size_t N> MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N)
+ template<std::size_t N>
+ constexpr MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N)
{
}
- operator Span<T>() const
+ constexpr operator Span<T>() const
{
return Span<T>(data_, size_);
}
@@ -472,7 +475,7 @@ template<typename T> class MutableSpan {
/**
* Returns the number of elements in the array.
*/
- int64_t size() const
+ constexpr int64_t size() const
{
return size_;
}
@@ -480,7 +483,7 @@ template<typename T> class MutableSpan {
/**
* Replace all elements in the referenced array with the given value.
*/
- void fill(const T &value)
+ constexpr void fill(const T &value)
{
initialized_fill_n(data_, size_, value);
}
@@ -489,7 +492,7 @@ template<typename T> class MutableSpan {
* Replace a subset of all elements with the given value. This invokes undefined behavior when
* one of the indices is out of bounds.
*/
- void fill_indices(Span<int64_t> indices, const T &value)
+ constexpr void fill_indices(Span<int64_t> indices, const T &value)
{
for (int64_t i : indices) {
BLI_assert(i < size_);
@@ -501,30 +504,30 @@ template<typename T> class MutableSpan {
* Returns a pointer to the beginning of the referenced array. This may be nullptr, when the size
* is zero.
*/
- T *data() const
+ constexpr T *data() const
{
return data_;
}
- T *begin() const
+ constexpr T *begin() const
{
return data_;
}
- T *end() const
+ constexpr T *end() const
{
return data_ + size_;
}
- std::reverse_iterator<T *> rbegin() const
+ constexpr std::reverse_iterator<T *> rbegin() const
{
return std::reverse_iterator<T *>(this->end());
}
- std::reverse_iterator<T *> rend() const
+ constexpr std::reverse_iterator<T *> rend() const
{
return std::reverse_iterator<T *>(this->begin());
}
- T &operator[](const int64_t index) const
+ constexpr T &operator[](const int64_t index) const
{
BLI_assert(index < this->size());
return data_[index];
@@ -534,7 +537,7 @@ template<typename T> class MutableSpan {
* Returns a contiguous part of the array. This invokes undefined behavior when the slice would
* go out of bounds.
*/
- MutableSpan slice(const int64_t start, const int64_t length) const
+ constexpr MutableSpan slice(const int64_t start, const int64_t length) const
{
BLI_assert(start + length <= this->size());
return MutableSpan(data_ + start, length);
@@ -544,7 +547,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan with n elements removed from the beginning. This invokes
* undefined behavior when the array is too small.
*/
- MutableSpan drop_front(const int64_t n) const
+ constexpr MutableSpan drop_front(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(n, this->size() - n);
@@ -554,7 +557,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan with n elements removed from the end. This invokes undefined
* behavior when the array is too small.
*/
- MutableSpan drop_back(const int64_t n) const
+ constexpr MutableSpan drop_back(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(0, this->size() - n);
@@ -564,7 +567,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan that only contains the first n elements. This invokes undefined
* behavior when the array is too small.
*/
- MutableSpan take_front(const int64_t n) const
+ constexpr MutableSpan take_front(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(0, n);
@@ -574,7 +577,7 @@ template<typename T> class MutableSpan {
* Return a new MutableSpan that only contains the last n elements. This invokes undefined
* behavior when the array is too small.
*/
- MutableSpan take_back(const int64_t n) const
+ constexpr MutableSpan take_back(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(this->size() - n, n);
@@ -584,7 +587,7 @@ template<typename T> class MutableSpan {
* Returns an (immutable) Span that references the same array. This is usually not needed,
* due to implicit conversions. However, sometimes automatic type deduction needs some help.
*/
- Span<T> as_span() const
+ constexpr Span<T> as_span() const
{
return Span<T>(data_, size_);
}
@@ -593,7 +596,7 @@ template<typename T> class MutableSpan {
* Utility to make it more convenient to iterate over all indices that can be used with this
* array.
*/
- IndexRange index_range() const
+ constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@@ -602,7 +605,7 @@ template<typename T> class MutableSpan {
* Returns a reference to the last element. This invokes undefined behavior when the array is
* empty.
*/
- T &last() const
+ constexpr T &last() const
{
BLI_assert(size_ > 0);
return data_[size_ - 1];
@@ -612,7 +615,7 @@ template<typename T> class MutableSpan {
* Does a linear search to count how often the value is in the array.
* Returns the number of occurrences.
*/
- int64_t count(const T &value) const
+ constexpr int64_t count(const T &value) const
{
int64_t counter = 0;
for (const T &element : *this) {
@@ -628,7 +631,7 @@ template<typename T> class MutableSpan {
* destination contains uninitialized data and T is not trivially copy constructible.
* The size of both spans is expected to be the same.
*/
- void copy_from(Span<T> values)
+ constexpr void copy_from(Span<T> values)
{
BLI_assert(size_ == values.size());
initialized_copy_n(values.data(), size_, data_);
@@ -637,7 +640,7 @@ template<typename T> class MutableSpan {
/**
* Returns a new span to the same underlying memory buffer. No conversions are done.
*/
- template<typename NewT> MutableSpan<NewT> cast() const
+ template<typename NewT> constexpr MutableSpan<NewT> cast() const
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
@@ -648,7 +651,7 @@ template<typename T> class MutableSpan {
/**
* Utilities to check that arrays have the same size in debug builds.
*/
-template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2 &v2)
+template<typename T1, typename T2> constexpr void assert_same_size(const T1 &v1, const T2 &v2)
{
UNUSED_VARS_NDEBUG(v1, v2);
#ifdef DEBUG
@@ -659,7 +662,7 @@ template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2
}
template<typename T1, typename T2, typename T3>
-void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
+constexpr void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
{
UNUSED_VARS_NDEBUG(v1, v2, v3);
#ifdef DEBUG
diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh
index 8597e54d03b..a2562c6100a 100644
--- a/source/blender/blenlib/BLI_string_ref.hh
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -64,7 +64,7 @@ class StringRefBase {
const char *data_;
int64_t size_;
- StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
+ constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
{
}
@@ -75,12 +75,12 @@ class StringRefBase {
/**
* Return the (byte-)length of the referenced string, without any null-terminator.
*/
- int64_t size() const
+ constexpr int64_t size() const
{
return size_;
}
- bool is_empty() const
+ constexpr bool is_empty() const
{
return size_ == 0;
}
@@ -88,12 +88,12 @@ class StringRefBase {
/**
* Return a pointer to the start of the string.
*/
- const char *data() const
+ constexpr const char *data() const
{
return data_;
}
- operator Span<char>() const
+ constexpr operator Span<char>() const
{
return Span<char>(data_, size_);
}
@@ -107,22 +107,22 @@ class StringRefBase {
return std::string(data_, static_cast<size_t>(size_));
}
- operator std::string_view() const
+ constexpr operator std::string_view() const
{
return std::string_view(data_, static_cast<size_t>(size_));
}
- const char *begin() const
+ constexpr const char *begin() const
{
return data_;
}
- const char *end() const
+ constexpr const char *end() const
{
return data_ + size_;
}
- IndexRange index_range() const
+ constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@@ -165,19 +165,19 @@ class StringRefBase {
/**
* Returns true when the string begins with the given prefix. Otherwise false.
*/
- bool startswith(StringRef prefix) const;
+ constexpr bool startswith(StringRef prefix) const;
/**
* Returns true when the string ends with the given suffix. Otherwise false.
*/
- bool endswith(StringRef suffix) const;
+ constexpr bool endswith(StringRef suffix) const;
- StringRef substr(int64_t start, const int64_t size) const;
+ constexpr StringRef substr(int64_t start, const int64_t size) const;
/**
* Get the first char in the string. This invokes undefined behavior when the string is empty.
*/
- const char &front() const
+ constexpr const char &front() const
{
BLI_assert(size_ >= 1);
return data_[0];
@@ -186,7 +186,7 @@ class StringRefBase {
/**
* Get the last char in the string. This invokes undefined behavior when the string is empty.
*/
- const char &back() const
+ constexpr const char &back() const
{
BLI_assert(size_ >= 1);
return data_[size_ - 1];
@@ -196,18 +196,18 @@ class StringRefBase {
* The behavior of those functions matches the standard library implementation of
* std::string_view.
*/
- int64_t find(char c, int64_t pos = 0) const;
- int64_t find(StringRef str, int64_t pos = 0) const;
- int64_t rfind(char c, int64_t pos = INT64_MAX) const;
- int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
- int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
- int64_t find_first_of(char c, int64_t pos = 0) const;
- int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
- int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
- int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
- int64_t find_first_not_of(char c, int64_t pos = 0) const;
- int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
- int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find(char c, int64_t pos = 0) const;
+ constexpr int64_t find(StringRef str, int64_t pos = 0) const;
+ constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const;
+ constexpr int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
+ constexpr int64_t find_first_of(char c, int64_t pos = 0) const;
+ constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
+ constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const;
+ constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
};
/**
@@ -216,7 +216,7 @@ class StringRefBase {
class StringRefNull : public StringRefBase {
public:
- StringRefNull() : StringRefBase("", 0)
+ constexpr StringRefNull() : StringRefBase("", 0)
{
}
@@ -226,7 +226,7 @@ class StringRefNull : public StringRefBase {
*/
StringRefNull(const char *str) : StringRefBase(str, static_cast<int64_t>(strlen(str)))
{
- BLI_assert(str != NULL);
+ BLI_assert(str != nullptr);
BLI_assert(data_[size_] == '\0');
}
@@ -234,7 +234,7 @@ class StringRefNull : public StringRefBase {
* Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior
* when the given size is not the correct size of the string.
*/
- StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
+ constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
{
BLI_assert(static_cast<int64_t>(strlen(str)) == size);
}
@@ -250,7 +250,7 @@ class StringRefNull : public StringRefBase {
/**
* Get the char at the given index.
*/
- char operator[](const int64_t index) const
+ constexpr char operator[](const int64_t index) const
{
BLI_assert(index >= 0);
/* Use '<=' instead of just '<', so that the null character can be accessed as well. */
@@ -263,7 +263,7 @@ class StringRefNull : public StringRefBase {
*
* This is like ->data(), but can only be called on a StringRefNull.
*/
- const char *c_str() const
+ constexpr const char *c_str() const
{
return data_;
}
@@ -274,25 +274,26 @@ class StringRefNull : public StringRefBase {
*/
class StringRef : public StringRefBase {
public:
- StringRef() : StringRefBase(nullptr, 0)
+ constexpr StringRef() : StringRefBase(nullptr, 0)
{
}
/**
* StringRefNull can be converted into StringRef, but not the other way around.
*/
- StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
+ constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
{
}
/**
* Create a StringRef from a null-terminated c-string.
*/
- StringRef(const char *str) : StringRefBase(str, str ? static_cast<int64_t>(strlen(str)) : 0)
+ constexpr StringRef(const char *str)
+ : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
{
}
- StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
+ constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
{
}
@@ -300,7 +301,7 @@ class StringRef : public StringRefBase {
* Create a StringRef from a start and end pointer. This invokes undefined behavior when the
* second point points to a smaller address than the first one.
*/
- StringRef(const char *begin, const char *one_after_end)
+ constexpr StringRef(const char *begin, const char *one_after_end)
: StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
{
BLI_assert(begin <= one_after_end);
@@ -314,7 +315,8 @@ class StringRef : public StringRefBase {
{
}
- StringRef(std::string_view view) : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
+ constexpr StringRef(std::string_view view)
+ : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
{
}
@@ -323,7 +325,7 @@ class StringRef : public StringRefBase {
*
* This is similar to std::string_view::remove_prefix.
*/
- StringRef drop_prefix(const int64_t n) const
+ constexpr StringRef drop_prefix(const int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= size_);
@@ -334,7 +336,7 @@ class StringRef : public StringRefBase {
* Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if
* the string does not begin with the given prefix.
*/
- StringRef drop_prefix(StringRef prefix) const
+ constexpr StringRef drop_prefix(StringRef prefix) const
{
BLI_assert(this->startswith(prefix));
return this->drop_prefix(prefix.size());
@@ -345,7 +347,7 @@ class StringRef : public StringRefBase {
*
* This is similar to std::string_view::remove_suffix.
*/
- StringRef drop_suffix(const int64_t n) const
+ constexpr StringRef drop_suffix(const int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= size_);
@@ -355,7 +357,7 @@ class StringRef : public StringRefBase {
/**
* Get the char at the given index.
*/
- char operator[](int64_t index) const
+ constexpr char operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
@@ -391,7 +393,7 @@ inline std::string operator+(StringRef a, StringRef b)
* not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
* std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
* Ideally, we only use StringRef in our code to avoid this problem altogether. */
-inline bool operator==(StringRef a, StringRef b)
+constexpr inline bool operator==(StringRef a, StringRef b)
{
if (a.size() != b.size()) {
return false;
@@ -399,27 +401,27 @@ inline bool operator==(StringRef a, StringRef b)
return STREQLEN(a.data(), b.data(), (size_t)a.size());
}
-inline bool operator!=(StringRef a, StringRef b)
+constexpr inline bool operator!=(StringRef a, StringRef b)
{
return !(a == b);
}
-inline bool operator<(StringRef a, StringRef b)
+constexpr inline bool operator<(StringRef a, StringRef b)
{
return std::string_view(a) < std::string_view(b);
}
-inline bool operator>(StringRef a, StringRef b)
+constexpr inline bool operator>(StringRef a, StringRef b)
{
return std::string_view(a) > std::string_view(b);
}
-inline bool operator<=(StringRef a, StringRef b)
+constexpr inline bool operator<=(StringRef a, StringRef b)
{
return std::string_view(a) <= std::string_view(b);
}
-inline bool operator>=(StringRef a, StringRef b)
+constexpr inline bool operator>=(StringRef a, StringRef b)
{
return std::string_view(a) >= std::string_view(b);
}
@@ -427,7 +429,7 @@ inline bool operator>=(StringRef a, StringRef b)
/**
* Return true when the string starts with the given prefix.
*/
-inline bool StringRefBase::startswith(StringRef prefix) const
+constexpr inline bool StringRefBase::startswith(StringRef prefix) const
{
if (size_ < prefix.size_) {
return false;
@@ -443,7 +445,7 @@ inline bool StringRefBase::startswith(StringRef prefix) const
/**
* Return true when the string ends with the given suffix.
*/
-inline bool StringRefBase::endswith(StringRef suffix) const
+constexpr inline bool StringRefBase::endswith(StringRef suffix) const
{
if (size_ < suffix.size_) {
return false;
@@ -460,8 +462,8 @@ inline bool StringRefBase::endswith(StringRef suffix) const
/**
* Return a new #StringRef containing only a sub-string of the original string.
*/
-inline StringRef StringRefBase::substr(const int64_t start,
- const int64_t max_size = INT64_MAX) const
+constexpr inline StringRef StringRefBase::substr(const int64_t start,
+ const int64_t max_size = INT64_MAX) const
{
BLI_assert(max_size >= 0);
BLI_assert(start >= 0);
@@ -469,7 +471,7 @@ inline StringRef StringRefBase::substr(const int64_t start,
return StringRef(data_ + start, substr_size);
}
-inline int64_t index_or_npos_to_int64(size_t index)
+constexpr inline int64_t index_or_npos_to_int64(size_t index)
{
/* The compiler will probably optimize this check away. */
if (index == std::string_view::npos) {
@@ -478,62 +480,62 @@ inline int64_t index_or_npos_to_int64(size_t index)
return static_cast<int64_t>(index);
}
-inline int64_t StringRefBase::find(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find(StringRef str, int64_t pos) const
+constexpr inline int64_t StringRefBase::find(StringRef str, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_of(chars, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
{
return this->find_first_of(StringRef(&c, 1), pos);
}
-inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_of(chars, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
{
return this->find_last_of(StringRef(&c, 1), pos);
}
-inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_not_of(chars, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
{
return this->find_first_not_of(StringRef(&c, 1), pos);
}
-inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_not_of(chars, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
{
return this->find_last_not_of(StringRef(&c, 1), pos);
}
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index d19b5393aa7..eefde1afefb 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -35,7 +35,6 @@ extern "C" {
#define BLENDER_MAX_THREADS 1024
struct ListBase;
-struct TaskScheduler;
/* Threading API */
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index 053dcb6faea..fe6d54ae9e5 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -315,13 +315,13 @@ class Vector {
return MutableSpan<T>(begin_, this->size());
}
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator Span<U>() const
{
return Span<U>(begin_, this->size());
}
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator MutableSpan<U>()
{
return MutableSpan<U>(begin_, this->size());
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 46a3ad87dfe..aa4c4efe7d4 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -203,6 +203,7 @@ set(SRC
BLI_heap_simple.h
BLI_index_mask.hh
BLI_index_range.hh
+ BLI_inplace_priority_queue.hh
BLI_iterator.h
BLI_jitter_2d.h
BLI_kdopbvh.h
@@ -390,6 +391,7 @@ if(WITH_GTESTS)
tests/BLI_heap_test.cc
tests/BLI_index_mask_test.cc
tests/BLI_index_range_test.cc
+ tests/BLI_inplace_priority_queue_test.cc
tests/BLI_kdopbvh_test.cc
tests/BLI_linear_allocator_test.cc
tests/BLI_linklist_lockfree_test.cc
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index f126c5a977b..0f90ad3a490 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -1076,6 +1076,25 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree)
return tree->epsilon;
}
+/**
+ * This function returns the bounding box of the BVH tree.
+ */
+void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3])
+{
+ BVHNode *root = tree->nodes[tree->totleaf];
+ if (root != NULL) {
+ const float bb_min[3] = {root->bv[0], root->bv[2], root->bv[4]};
+ const float bb_max[3] = {root->bv[1], root->bv[3], root->bv[5]};
+ copy_v3_v3(r_bb_min, bb_min);
+ copy_v3_v3(r_bb_max, bb_max);
+ }
+ else {
+ BLI_assert(false);
+ zero_v3(r_bb_min);
+ zero_v3(r_bb_max);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/tests/BLI_index_range_test.cc b/source/blender/blenlib/tests/BLI_index_range_test.cc
index d472ded0f18..ddaa067f50e 100644
--- a/source/blender/blenlib/tests/BLI_index_range_test.cc
+++ b/source/blender/blenlib/tests/BLI_index_range_test.cc
@@ -140,4 +140,11 @@ TEST(index_range, AsSpan)
EXPECT_EQ(span[3], 7);
}
+TEST(index_range, constexpr_)
+{
+ constexpr IndexRange range = IndexRange(1, 1);
+ std::array<int, range[0]> compiles = {1};
+ BLI_STATIC_ASSERT(range.size() == 1, "");
+ EXPECT_EQ(compiles[0], 1);
+}
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc b/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc
new file mode 100644
index 00000000000..3adf12f36a7
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc
@@ -0,0 +1,113 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_inplace_priority_queue.hh"
+#include "BLI_rand.hh"
+
+namespace blender::tests {
+
+TEST(inplace_priority_queue, BuildSmall)
+{
+ Array<int> values = {1, 5, 2, 8, 5, 6, 5, 4, 3, 6, 7, 3};
+ InplacePriorityQueue<int> priority_queue{values};
+
+ EXPECT_EQ(priority_queue.peek(), 8);
+ EXPECT_EQ(priority_queue.pop(), 8);
+ EXPECT_EQ(priority_queue.peek(), 7);
+ EXPECT_EQ(priority_queue.pop(), 7);
+ EXPECT_EQ(priority_queue.pop(), 6);
+ EXPECT_EQ(priority_queue.pop(), 6);
+ EXPECT_EQ(priority_queue.pop(), 5);
+}
+
+TEST(inplace_priority_queue, DecreasePriority)
+{
+ Array<int> values = {5, 2, 7, 4};
+ InplacePriorityQueue<int> priority_queue(values);
+
+ EXPECT_EQ(priority_queue.peek(), 7);
+ values[2] = 0;
+ EXPECT_EQ(priority_queue.peek(), 0);
+ priority_queue.priority_decreased(2);
+ EXPECT_EQ(priority_queue.peek(), 5);
+}
+
+TEST(inplace_priority_queue, IncreasePriority)
+{
+ Array<int> values = {5, 2, 7, 4};
+ InplacePriorityQueue<int> priority_queue(values);
+
+ EXPECT_EQ(priority_queue.peek(), 7);
+ values[1] = 10;
+ EXPECT_EQ(priority_queue.peek(), 7);
+ priority_queue.priority_increased(1);
+ EXPECT_EQ(priority_queue.peek(), 10);
+}
+
+TEST(inplace_priority_queue, PopAll)
+{
+ RandomNumberGenerator rng;
+ Vector<int> values;
+ const int amount = 1000;
+ for (int i = 0; i < amount; i++) {
+ values.append(rng.get_int32() % amount);
+ }
+
+ InplacePriorityQueue<int> priority_queue(values);
+
+ int last_value = amount;
+ while (!priority_queue.is_empty()) {
+ const int value = priority_queue.pop();
+ EXPECT_LE(value, last_value);
+ last_value = value;
+ }
+}
+
+TEST(inplace_priority_queue, ManyPriorityChanges)
+{
+ RandomNumberGenerator rng;
+ Vector<int> values;
+ const int amount = 1000;
+ for (int i = 0; i < amount; i++) {
+ values.append(rng.get_int32() % amount);
+ }
+
+ InplacePriorityQueue<int> priority_queue(values);
+
+ for (int i = 0; i < amount; i++) {
+ const int index = rng.get_int32() % amount;
+ const int new_priority = rng.get_int32() % amount;
+ values[index] = new_priority;
+ priority_queue.priority_changed(index);
+ }
+
+ int last_value = amount;
+ while (!priority_queue.is_empty()) {
+ const int value = priority_queue.pop();
+ EXPECT_LE(value, last_value);
+ last_value = value;
+ }
+}
+
+TEST(inplace_priority_queue, IndicesAccess)
+{
+ Array<int> values = {4, 6, 2, 4, 8, 1, 10, 2, 5};
+ InplacePriorityQueue<int> priority_queue(values);
+
+ EXPECT_EQ(priority_queue.active_indices().size(), 9);
+ EXPECT_EQ(priority_queue.inactive_indices().size(), 0);
+ EXPECT_EQ(priority_queue.all_indices().size(), 9);
+ EXPECT_EQ(priority_queue.pop(), 10);
+ EXPECT_EQ(priority_queue.active_indices().size(), 8);
+ EXPECT_EQ(priority_queue.inactive_indices().size(), 1);
+ EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 10);
+ EXPECT_EQ(priority_queue.all_indices().size(), 9);
+ EXPECT_EQ(priority_queue.pop(), 8);
+ EXPECT_EQ(priority_queue.inactive_indices().size(), 2);
+ EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 8);
+ EXPECT_EQ(values[priority_queue.inactive_indices()[1]], 10);
+ EXPECT_EQ(priority_queue.all_indices().size(), 9);
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
index fcef2f8688a..23415e69b04 100644
--- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc
+++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
@@ -158,4 +158,15 @@ static_assert(is_convertible_pointer_v<int **, int **const>);
static_assert(is_convertible_pointer_v<int **, int *const *>);
static_assert(is_convertible_pointer_v<int **, int const *const *>);
+static_assert(is_span_convertible_pointer_v<int *, int *>);
+static_assert(is_span_convertible_pointer_v<int *, const int *>);
+static_assert(!is_span_convertible_pointer_v<const int *, int *>);
+static_assert(is_span_convertible_pointer_v<const int *, const int *>);
+static_assert(is_span_convertible_pointer_v<const int *, const void *>);
+static_assert(!is_span_convertible_pointer_v<const int *, void *>);
+static_assert(is_span_convertible_pointer_v<int *, void *>);
+static_assert(is_span_convertible_pointer_v<int *, const void *>);
+static_assert(!is_span_convertible_pointer_v<TestBaseClass *, TestChildClass *>);
+static_assert(!is_span_convertible_pointer_v<TestChildClass *, TestBaseClass *>);
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_span_test.cc b/source/blender/blenlib/tests/BLI_span_test.cc
index 9a8d9df7873..d1c9f312b97 100644
--- a/source/blender/blenlib/tests/BLI_span_test.cc
+++ b/source/blender/blenlib/tests/BLI_span_test.cc
@@ -337,4 +337,19 @@ TEST(span, MutableReverseIterator)
EXPECT_EQ_ARRAY(src.data(), Span({14, 15, 16, 17}).data(), 4);
}
+TEST(span, constexpr_)
+{
+ static constexpr std::array<int, 3> src = {3, 2, 1};
+ constexpr Span<int> span(src);
+ BLI_STATIC_ASSERT(span[2] == 1, "");
+ BLI_STATIC_ASSERT(span.size() == 3, "");
+ BLI_STATIC_ASSERT(span.slice(1, 2).size() == 2, "");
+ BLI_STATIC_ASSERT(span.has_duplicates__linear_search() == false, "");
+
+ std::integral_constant<bool, span.first_index(1) == 2> ic;
+ BLI_STATIC_ASSERT(ic.value, "");
+
+ EXPECT_EQ(span.slice(1, 2).size(), 2);
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_string_ref_test.cc b/source/blender/blenlib/tests/BLI_string_ref_test.cc
index 2d488feff71..401a7bc1118 100644
--- a/source/blender/blenlib/tests/BLI_string_ref_test.cc
+++ b/source/blender/blenlib/tests/BLI_string_ref_test.cc
@@ -298,4 +298,12 @@ TEST(string_ref, ToStringView)
EXPECT_EQ(view, "hello");
}
+TEST(string_ref, constexpr_)
+{
+ constexpr StringRef sref("World");
+ BLI_STATIC_ASSERT(sref[2] == 'r', "");
+ BLI_STATIC_ASSERT(sref.size() == 5, "");
+ std::array<int, static_cast<std::size_t>(sref.find_first_of('o'))> compiles = {1};
+ EXPECT_EQ(compiles[0], 1);
+}
} // namespace blender::tests
diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h
index c4480e2c544..ea0532d884b 100644
--- a/source/blender/blenloader/BLO_read_write.h
+++ b/source/blender/blenloader/BLO_read_write.h
@@ -160,6 +160,7 @@ void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_p
void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr);
void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr);
void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr);
+void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr);
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr);
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr);
void BLO_write_string(BlendWriter *writer, const char *data_ptr);
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 3e7cdb30e1f..c724cc32051 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -34,16 +34,13 @@
#include "zlib.h"
struct BLOCacheStorage;
-struct GSet;
struct IDNameLib_Map;
struct Key;
struct MemFile;
struct Object;
struct OldNewMap;
-struct PartEff;
struct ReportList;
struct UserDef;
-struct View3D;
typedef struct IDNameLib_Map IDNameLib_Map;
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index d00c5225299..4df681002a0 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -74,6 +74,29 @@
/* Make preferences read-only, use versioning_userdef.c. */
#define U (*((const UserDef *)&U))
+static eSpaceSeq_Proxy_RenderSize get_sequencer_render_size(Main *bmain)
+{
+ eSpaceSeq_Proxy_RenderSize render_size = 100;
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ render_size = sseq->render_size;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return render_size;
+}
+
/* image_size is width or height depending what RNA property is converted - X or Y. */
static void seq_convert_transform_animation(const Scene *scene,
const char *path,
@@ -212,6 +235,84 @@ static void seq_convert_transform_crop_lb(const Scene *scene,
}
}
+static void seq_convert_transform_animation_2(const Scene *scene,
+ const char *path,
+ const float scale_to_fit_factor)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL) {
+ return;
+ }
+
+ FCurve *fcu = BKE_fcurve_find(&scene->adt->action->curves, path, 0);
+ if (fcu != NULL && !BKE_fcurve_is_empty(fcu)) {
+ BezTriple *bezt = fcu->bezt;
+ for (int i = 0; i < fcu->totvert; i++, bezt++) {
+ /* Same math as with old_image_center_*, but simplified. */
+ bezt->vec[1][1] *= scale_to_fit_factor;
+ }
+ }
+}
+
+static void seq_convert_transform_crop_2(const Scene *scene,
+ Sequence *seq,
+ const eSpaceSeq_Proxy_RenderSize render_size)
+{
+ const StripElem *s_elem = SEQ_render_give_stripelem(seq, seq->start);
+ if (s_elem == NULL) {
+ return;
+ }
+
+ StripCrop *c = seq->strip->crop;
+ StripTransform *t = seq->strip->transform;
+ int image_size_x = s_elem->orig_width;
+ int image_size_y = s_elem->orig_height;
+
+ if (SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(render_size))) {
+ image_size_x /= SEQ_rendersize_to_scale_factor(render_size);
+ image_size_y /= SEQ_rendersize_to_scale_factor(render_size);
+ }
+
+ /* Calculate scale factor, so image fits in preview area with original aspect ratio. */
+ const float scale_to_fit_factor = MIN2((float)scene->r.xsch / (float)image_size_x,
+ (float)scene->r.ysch / (float)image_size_y);
+ t->scale_x *= scale_to_fit_factor;
+ t->scale_y *= scale_to_fit_factor;
+ c->top /= scale_to_fit_factor;
+ c->bottom /= scale_to_fit_factor;
+ c->left /= scale_to_fit_factor;
+ c->right /= scale_to_fit_factor;
+
+ char name_esc[(sizeof(seq->name) - 2) * 2], *path;
+ BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
+ path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.min_x", name_esc);
+ seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor);
+ MEM_freeN(path);
+ path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.max_x", name_esc);
+ seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor);
+ MEM_freeN(path);
+ path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.min_y", name_esc);
+ seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor);
+ MEM_freeN(path);
+ path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.max_x", name_esc);
+ seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor);
+ MEM_freeN(path);
+}
+
+static void seq_convert_transform_crop_lb_2(const Scene *scene,
+ const ListBase *lb,
+ const eSpaceSeq_Proxy_RenderSize render_size)
+{
+
+ LISTBASE_FOREACH (Sequence *, seq, lb) {
+ if (seq->type != SEQ_TYPE_SOUND_RAM) {
+ seq_convert_transform_crop_2(scene, seq, render_size);
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ seq_convert_transform_crop_lb_2(scene, &seq->seqbase, render_size);
+ }
+ }
+}
+
void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
{
if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) {
@@ -441,25 +542,35 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
if (!MAIN_VERSION_ATLEAST(bmain, 292, 2)) {
- eSpaceSeq_Proxy_RenderSize render_size = 100;
+ eSpaceSeq_Proxy_RenderSize render_size = get_sequencer_render_size(bmain);
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
- switch (sl->spacetype) {
- case SPACE_SEQ: {
- SpaceSeq *sseq = (SpaceSeq *)sl;
- render_size = sseq->render_size;
- break;
- }
- }
- }
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != NULL) {
+ seq_convert_transform_crop_lb(scene, &scene->ed->seqbase, render_size);
}
}
+ }
+ if (!MAIN_VERSION_ATLEAST(bmain, 292, 8)) {
+ /* Systematically rebuild posebones to ensure consistent ordering matching the one of bones in
+ * Armature obdata. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_ARMATURE) {
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
+ }
+ }
+
+ /* Wet Paint Radius Factor */
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->ob_mode & OB_MODE_SCULPT && br->wet_paint_radius_factor == 0.0f) {
+ br->wet_paint_radius_factor = 1.0f;
+ }
+ }
+
+ eSpaceSeq_Proxy_RenderSize render_size = get_sequencer_render_size(bmain);
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->ed != NULL) {
- seq_convert_transform_crop_lb(scene, &scene->ed->seqbase, render_size);
+ seq_convert_transform_crop_lb_2(scene, &scene->ed->seqbase, render_size);
}
}
}
@@ -476,21 +587,6 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
*/
{
/* Keep this block, even when empty. */
-
- /* Systematically rebuild posebones to ensure consistent ordering matching the one of bones in
- * Armature obdata. */
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->type == OB_ARMATURE) {
- BKE_pose_rebuild(bmain, ob, ob->data, true);
- }
- }
- }
-
- /* Wet Paint Radius Factor */
- for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
- if (br->ob_mode & OB_MODE_SCULPT && br->wet_paint_radius_factor == 0.0f) {
- br->wet_paint_radius_factor = 1.0f;
- }
}
}
@@ -1234,18 +1330,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - "versioning_userdef.c", #blo_do_versions_userdef
- * - "versioning_userdef.c", #do_versions_theme
- *
- * \note Keep this message at the bottom of the function.
- */
- {
- /* Keep this block, even when empty. */
-
+ if (!MAIN_VERSION_ATLEAST(bmain, 292, 7)) {
/* Make all IDProperties used as interface of geometry node trees overridable. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
@@ -1301,5 +1386,47 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Overlay elements in the sequencer. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ sseq->flag |= (SEQ_SHOW_STRIP_OVERLAY | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_SOURCE |
+ SEQ_SHOW_STRIP_DURATION);
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 292, 8)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (STREQ(node->idname, "GeometryNodeRandomAttribute")) {
+ STRNCPY(node->idname, "GeometryNodeAttributeRandomize");
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != NULL) {
+ scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init();
+ }
+ }
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index f89a5be27de..198f65b9794 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -182,7 +182,8 @@ static void blo_update_defaults_screen(bScreen *screen,
}
else if (area->spacetype == SPACE_SEQ) {
SpaceSeq *seq = area->spacedata.first;
- seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT;
+ seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY |
+ SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_DURATION;
}
else if (area->spacetype == SPACE_TEXT) {
/* Show syntax and line numbers in Script workspace text editor. */
@@ -738,6 +739,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_ERASER;
}
+ brush_name = "Multires Displacement Smear";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_SMEAR;
+ }
+
/* Use the same tool icon color in the brush cursor */
for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
if (brush->ob_mode & OB_MODE_SCULPT) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index e7d55538f7e..0a4f2fde93f 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1374,6 +1374,11 @@ void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
BLO_write_raw(writer, sizeof(float) * (size_t)num, data_ptr);
}
+void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr)
+{
+ BLO_write_raw(writer, sizeof(double) * (size_t)num, data_ptr);
+}
+
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
{
BLO_write_raw(writer, sizeof(void *) * (size_t)num, data_ptr);
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index f894bdabba4..4e618d8625d 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -39,7 +39,6 @@ struct Main;
struct Object;
struct Scene;
struct Simulation;
-struct ViewLayer;
struct bNodeTree;
#include "BLI_sys_types.h"
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index cbfb51c59a6..5587379089c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -45,7 +45,6 @@
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
-struct Base;
struct CacheFile;
struct Camera;
struct Collection;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
index 1f58c54dbf4..ec661360fdf 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -25,8 +25,6 @@
#pragma once
-struct Main;
-
namespace blender {
namespace deg {
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
index 17392c0de0b..fde0c80ab37 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.h
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -24,14 +24,14 @@
#include "BLI_sys_types.h" /* for bool */
+struct BlendDataReader;
+struct BlendWriter;
struct EEVEE_Data;
struct EEVEE_ViewLayerData;
struct LightCache;
struct Scene;
struct SceneEEVEE;
struct ViewLayer;
-struct BlendWriter;
-struct BlendDataReader;
/* Light Bake */
struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 04128dc157e..d0bd56b42dd 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -39,10 +39,7 @@ extern DrawEngineType draw_engine_gpencil_type;
struct GPENCIL_Data;
struct GPENCIL_StorageList;
struct GPUBatch;
-struct GPUVertBuf;
-struct GPUVertFormat;
struct GpencilBatchCache;
-struct MaterialGPencilStyle;
struct Object;
struct RenderEngine;
struct RenderLayer;
diff --git a/source/blender/draw/engines/image/image_private.h b/source/blender/draw/engines/image/image_private.h
index d5821cc5d70..76a94e68da1 100644
--- a/source/blender/draw/engines/image/image_private.h
+++ b/source/blender/draw/engines/image/image_private.h
@@ -25,11 +25,9 @@ extern "C" {
#endif
/* Forward declarations */
-struct GPUBatch;
struct GPUTexture;
struct ImBuf;
struct Image;
-struct rcti;
/* *********** LISTS *********** */
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index fbe71900915..4df2ba1e913 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -64,7 +64,6 @@
#include "DEG_depsgraph.h"
struct GPUBatch;
-struct GPUFrameBuffer;
struct GPUMaterial;
struct GPUShader;
struct GPUTexture;
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 23dd47d4ab5..a059ac32311 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -22,10 +22,8 @@
#pragma once
-struct DRWPass;
struct DRWShadingGroup;
struct FluidModifierData;
-struct GPUMaterial;
struct ModifierData;
struct Object;
struct ParticleSystem;
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 988975bd399..ffc565d0514 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -2073,7 +2073,6 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
* for the image editor this is when showing UV's.*/
const bool do_populate_loop = (DST.draw_ctx.space_data->spacetype == SPACE_IMAGE);
const bool do_annotations = drw_draw_show_annotation();
- const bool do_region_callbacks = (DST.draw_ctx.space_data->spacetype != SPACE_IMAGE);
const bool do_draw_gizmos = (DST.draw_ctx.space_data->spacetype != SPACE_IMAGE);
/* Get list of enabled engines */
@@ -2125,7 +2124,7 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
/* Start Drawing */
DRW_state_reset();
- if (do_region_callbacks && DST.draw_ctx.evil_C) {
+ if (DST.draw_ctx.evil_C) {
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_PRE_VIEW);
}
@@ -2147,10 +2146,8 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
if (do_annotations) {
ED_annotation_draw_view2d(DST.draw_ctx.evil_C, true);
}
- if (do_region_callbacks) {
- GPU_depth_test(GPU_DEPTH_NONE);
- ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW);
- }
+ GPU_depth_test(GPU_DEPTH_NONE);
+ ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW);
GPU_matrix_pop_projection();
/* Callback can be nasty and do whatever they want with the state.
* Don't trust them! */
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 3617f20763e..9bca294cf30 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -283,8 +283,8 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
tgpil->gpl = gpl;
- tgpil->prevFrame = gpl->actframe;
- tgpil->nextFrame = gpl->actframe->next;
+ tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe);
+ tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next);
BLI_addtail(&tgpi->ilayers, tgpil);
@@ -326,24 +326,25 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
valid = false;
}
- /* create new stroke */
- new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
-
if (valid) {
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
- new_stroke->points = MEM_recallocN(new_stroke->points,
- sizeof(*new_stroke->points) * gps_to->totpoints);
- if (new_stroke->dvert != NULL) {
- new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
- sizeof(*new_stroke->dvert) * gps_to->totpoints);
- }
- new_stroke->totpoints = gps_to->totpoints;
+ BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true);
}
- /* update points position */
+ if (gps_to->totpoints > gps_from->totpoints) {
+ BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true);
+ }
+
+ /* Create new stroke. */
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
+
+ /* Update points position. */
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
}
else {
+ /* Create new stroke. */
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
+
/* need an empty stroke to keep index correct for lookup, but resize to smallest size */
new_stroke->totpoints = 0;
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
@@ -443,12 +444,16 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
/* finally, free memory used by temp data */
LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
+ BKE_gpencil_free_strokes(tgpil->prevFrame);
+ BKE_gpencil_free_strokes(tgpil->nextFrame);
BKE_gpencil_free_strokes(tgpil->interFrame);
- MEM_freeN(tgpil->interFrame);
+ MEM_SAFE_FREE(tgpil->prevFrame);
+ MEM_SAFE_FREE(tgpil->nextFrame);
+ MEM_SAFE_FREE(tgpil->interFrame);
}
BLI_freelistN(&tgpi->ilayers);
- MEM_freeN(tgpi);
+ MEM_SAFE_FREE(tgpi);
}
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
@@ -992,8 +997,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* store extremes */
- prevFrame = gpl->actframe;
- nextFrame = gpl->actframe->next;
+ prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe);
+ nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next);
/* Loop over intermediary frames and create the interpolation */
for (cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) {
@@ -1049,28 +1054,17 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
}
- /* create new stroke */
- bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
-
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
- /* free weights of removed points */
- if (new_stroke->dvert != NULL) {
- BKE_defvert_array_free_elems(new_stroke->dvert + gps_to->totpoints,
- gps_from->totpoints - gps_to->totpoints);
- }
-
- new_stroke->points = MEM_recallocN(new_stroke->points,
- sizeof(*new_stroke->points) * gps_to->totpoints);
-
- if (new_stroke->dvert != NULL) {
- new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
- sizeof(*new_stroke->dvert) * gps_to->totpoints);
- }
-
- new_stroke->totpoints = gps_to->totpoints;
+ BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true);
+ }
+ if (gps_to->totpoints > gps_from->totpoints) {
+ BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true);
}
+ /* create new stroke */
+ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
+
/* update points position */
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
@@ -1081,6 +1075,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
BLI_addtail(&interFrame->strokes, new_stroke);
}
}
+
+ BKE_gpencil_free_strokes(prevFrame);
+ BKE_gpencil_free_strokes(nextFrame);
+ MEM_SAFE_FREE(prevFrame);
+ MEM_SAFE_FREE(nextFrame);
}
/* notifiers */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 3501acd4fdf..0c4576096fb 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -31,7 +31,6 @@ struct Base;
struct Bone;
struct Depsgraph;
struct EditBone;
-struct IDProperty;
struct ListBase;
struct Main;
struct Mesh;
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 3288cf11cb0..7b240e0569f 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -28,8 +28,9 @@ extern "C" {
#endif
struct ARegion;
-struct FileSelectParams;
struct FileAssetSelectParams;
+struct FileSelectParams;
+struct FileDirEntry;
struct Scene;
struct ScrArea;
struct SpaceFile;
@@ -154,6 +155,7 @@ struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win,
int ED_path_extension_type(const char *path);
int ED_file_extension_icon(const char *path);
+int ED_file_icon(const struct FileDirEntry *file);
void ED_file_read_bookmarks(void);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index be2f714dfe1..1b7caf27ecf 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -51,7 +51,6 @@ struct ScrArea;
struct SnapObjectContext;
struct ToolSettings;
struct View3D;
-struct ViewLayer;
struct bContext;
struct Material;
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index c1d3a17b9b6..b139b0765a3 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -34,12 +34,10 @@ struct ARegion;
struct ImBuf;
struct Image;
struct ImageUser;
-struct LinkNodePair;
struct Main;
struct ReportList;
struct Scene;
struct SpaceImage;
-struct ViewLayer;
struct bContext;
struct wmOperator;
struct wmWindowManager;
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 2e9b711c99a..f9358f62274 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -53,7 +53,6 @@ struct uiLayout;
struct wmKeyConfig;
struct wmOperator;
struct wmOperatorType;
-struct wmWindowManager;
/* object_edit.c */
/* context.object */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index dc1c43c0337..20417634020 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -239,6 +239,7 @@ void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
void ED_screen_full_prevspace(struct bContext *C, ScrArea *area);
void ED_screen_full_restore(struct bContext *C, ScrArea *area);
+ScrArea *ED_screen_state_maximized_create(struct bContext *C);
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *area,
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 0ea86e006e0..ca3e351a052 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -32,7 +32,6 @@ extern "C" {
struct Object;
struct bContext;
struct wmKeyConfig;
-struct wmMsgBus;
struct wmOperatorType;
void ED_keymap_transform(struct wmKeyConfig *keyconf);
@@ -108,7 +107,6 @@ bool calculateTransformCenter(struct bContext *C,
struct Object;
struct Scene;
-struct wmGizmoGroup;
struct wmGizmoGroupType;
/* UNUSED */
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index ebaa32941f2..b7174964ef6 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -31,7 +31,6 @@ struct BMVert;
struct ARegion;
struct Depsgraph;
struct ListBase;
-struct Main;
struct Object;
struct Scene;
struct View3D;
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index d74a80045f1..ca6b4bdc618 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -54,6 +54,7 @@ void ED_spacedata_id_remap(struct ScrArea *area,
void ED_OT_flush_edits(struct wmOperatorType *ot);
void ED_OT_lib_id_load_custom_preview(struct wmOperatorType *ot);
+void ED_OT_lib_id_generate_preview(struct wmOperatorType *ot);
/* ************** XXX OLD CRUFT WARNING ************* */
diff --git a/source/blender/editors/include/ED_util_imbuf.h b/source/blender/editors/include/ED_util_imbuf.h
index d142d3d6425..4bbaa68e849 100644
--- a/source/blender/editors/include/ED_util_imbuf.h
+++ b/source/blender/editors/include/ED_util_imbuf.h
@@ -31,7 +31,6 @@ extern "C" {
#endif
struct ARegion;
-struct Main;
struct bContext;
struct wmEvent;
struct wmOperator;
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index d08bc0b0b3d..4de97411059 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -33,7 +33,6 @@ struct BMEditMesh;
struct BMFace;
struct BMLoop;
struct BMesh;
-struct Depsgraph;
struct Image;
struct ImageUser;
struct Main;
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 13687bf0450..a4856845a65 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -41,8 +41,6 @@ struct Camera;
struct CustomData_MeshMasks;
struct Depsgraph;
struct EditBone;
-struct GPUOffScreen;
-struct GPUViewport;
struct ID;
struct MVert;
struct Main;
@@ -55,7 +53,6 @@ struct RenderEngineType;
struct Scene;
struct ScrArea;
struct View3D;
-struct View3DShading;
struct ViewContext;
struct ViewLayer;
struct bContext;
@@ -64,8 +61,6 @@ struct bScreen;
struct rctf;
struct rcti;
struct wmGizmo;
-struct wmOperator;
-struct wmOperatorType;
struct wmWindow;
struct wmWindowManager;
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 83e94664c0b..7c128cbf1e6 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -50,7 +50,6 @@ struct PointerRNA;
struct PropertyRNA;
struct ReportList;
struct ResultBLF;
-struct ScrArea;
struct bContext;
struct bContextStore;
struct bNode;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 1c09dc6f4df..899f4a6ddb1 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1416,7 +1416,7 @@ static void icon_set_image(const bContext *C,
const bool delay = prv_img->rect[size] != NULL;
icon_create_rect(prv_img, size);
- if (use_job && BKE_previewimg_id_supports_jobs(id)) {
+ if (use_job && (!id || BKE_previewimg_id_supports_jobs(id))) {
/* Job (background) version */
ED_preview_icon_job(
C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size], delay);
@@ -2199,6 +2199,9 @@ int UI_icon_from_library(const ID *id)
if (ID_IS_OVERRIDE_LIBRARY(id)) {
return ICON_LIBRARY_DATA_OVERRIDE;
}
+ if (ID_IS_ASSET(id)) {
+ return ICON_MAT_SPHERE_SKY;
+ }
return ICON_NONE;
}
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 8ec9f7af184..5caa7c71e83 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2527,7 +2527,7 @@ static bool convert_proxy_to_override_poll(bContext *C)
return obact != NULL && obact->proxy != NULL;
}
-static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op))
+static int convert_proxy_to_override_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -2541,6 +2541,15 @@ static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op))
const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, view_layer, ob_proxy);
+ if (!success) {
+ BKE_reportf(
+ op->reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Could not create a library override from proxy '%s' (might use already local data?)",
+ ob_proxy->id.name + 2);
+ return OPERATOR_CANCELLED;
+ }
+
/* Remove the instance empty from this scene, the items now have an overridden collection
* instead. */
if (success && is_override_instancing_object) {
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 3d6a6abfe0d..23f1718cb2e 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -741,6 +741,9 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *
RNA_enum_items_add_value(
&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_SELECT);
}
+ }
+
+ if (BKE_modifiers_is_deformed_by_armature(ob)) {
if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) {
RNA_enum_items_add_value(
&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_DEFORM);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 3dbf70aa4bc..a035ee3e342 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -150,31 +150,31 @@ static void image_buffer_rect_update(RenderJob *rj,
}
/* xmin here is first subrect x coord, xmax defines subrect width */
- xmin = renrect->xmin + rr->crop;
- xmax = renrect->xmax - xmin + rr->crop;
+ xmin = renrect->xmin;
+ xmax = renrect->xmax - xmin;
if (xmax < 2) {
return;
}
- ymin = renrect->ymin + rr->crop;
- ymax = renrect->ymax - ymin + rr->crop;
+ ymin = renrect->ymin;
+ ymax = renrect->ymax - ymin;
if (ymax < 2) {
return;
}
renrect->ymin = renrect->ymax;
}
else {
- xmin = ymin = rr->crop;
- xmax = rr->rectx - 2 * rr->crop;
- ymax = rr->recty - 2 * rr->crop;
+ xmin = ymin = 0;
+ xmax = rr->rectx;
+ ymax = rr->recty;
}
/* xmin ymin is in tile coords. transform to ibuf */
- rxmin = rr->tilerect.xmin + xmin;
+ rxmin = rr->tilerect.xmin;
if (rxmin >= ibuf->x) {
return;
}
- rymin = rr->tilerect.ymin + ymin;
+ rymin = rr->tilerect.ymin;
if (rymin >= ibuf->y) {
return;
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 6be2fb8004b..be52874ed0b 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1133,12 +1133,11 @@ void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene)
ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
{
- wmWindow *win = CTX_wm_window(C);
ScrArea *newsa = NULL;
SpaceLink *newsl;
if (!area || area->full == NULL) {
- newsa = ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED);
+ newsa = ED_screen_state_maximized_create(C);
}
if (!newsa) {
@@ -1149,11 +1148,11 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
newsl = newsa->spacedata.first;
/* Tag the active space before changing, so we can identify it when user wants to go back. */
- if ((newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) {
+ if (newsl && (newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) {
newsl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE;
}
- ED_area_newspace(C, newsa, type, newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY);
+ ED_area_newspace(C, newsa, type, (newsl && newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY));
return newsa;
}
@@ -1217,13 +1216,108 @@ void ED_screen_full_restore(bContext *C, ScrArea *area)
}
/**
- * this function toggles: if area is maximized/full then the parent will be restored
+ * \param toggle_area: If this is set, its space data will be swapped with the one of the new emtpy
+ * area, when toggling back it can be swapped back again.
+ * \return The newly created screen with the non-normal area.
+ */
+static bScreen *screen_state_to_nonnormal(bContext *C,
+ wmWindow *win,
+ ScrArea *toggle_area,
+ int state)
+{
+ Main *bmain = CTX_data_main(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+
+ /* change from SCREENNORMAL to new state */
+ WorkSpaceLayout *layout_new;
+ ScrArea *newa;
+ char newname[MAX_ID_NAME - 2];
+
+ BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL));
+
+ bScreen *oldscreen = WM_window_get_active_screen(win);
+
+ oldscreen->state = state;
+ BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
+
+ layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
+
+ bScreen *screen = BKE_workspace_layout_screen_get(layout_new);
+ screen->state = state;
+ screen->redraws_flag = oldscreen->redraws_flag;
+ screen->temp = oldscreen->temp;
+ screen->flag = oldscreen->flag;
+
+ /* timer */
+ screen->animtimer = oldscreen->animtimer;
+ oldscreen->animtimer = NULL;
+
+ newa = (ScrArea *)screen->areabase.first;
+
+ /* swap area */
+ if (toggle_area) {
+ ED_area_data_swap(newa, toggle_area);
+ newa->flag = toggle_area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+ }
+
+ if (state == SCREENFULL) {
+ /* temporarily hide global areas */
+ LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
+ glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
+ }
+ /* temporarily hide the side panels/header */
+ LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) {
+ region->flagfullscreen = region->flag;
+
+ if (ELEM(region->regiontype,
+ RGN_TYPE_UI,
+ RGN_TYPE_HEADER,
+ RGN_TYPE_TOOL_HEADER,
+ RGN_TYPE_FOOTER,
+ RGN_TYPE_TOOLS,
+ RGN_TYPE_NAV_BAR,
+ RGN_TYPE_EXECUTE)) {
+ region->flag |= RGN_FLAG_HIDDEN;
+ }
+ }
+ }
+
+ if (toggle_area) {
+ toggle_area->full = oldscreen;
+ }
+ newa->full = oldscreen;
+
+ ED_screen_change(C, screen);
+ ED_area_tag_refresh(newa);
+
+ return screen;
+}
+
+/**
+ * Create a new temporary screen with a maximized, empty area.
+ * This can be closed with #ED_screen_state_toggle().
+ *
+ * Use this to just create a new maximized screen/area, rather than maximizing an existing one.
+ * Otherwise, maximize with #ED_screen_state_toggle().
+ */
+ScrArea *ED_screen_state_maximized_create(bContext *C)
+{
+ bScreen *screen = screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED);
+ return screen->areabase.first;
+}
+
+/**
+ * This function toggles: if area is maximized/full then the parent will be restored.
+ *
+ * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to
+ * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a
+ * specific area. In the former case, space data of the maximized and non-maximized area should be
+ * independent, in the latter it should be the same.
*
* \warning \a area may be freed.
*/
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state)
{
- Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -1257,7 +1351,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
screen->state = SCREENNORMAL;
screen->flag = oldscreen->flag;
- /* find old area to restore from */
+ /* Find old area we may have swapped dummy space data to. It's swapped back here. */
ScrArea *fullsa = NULL;
LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) {
/* area to restore from is always first */
@@ -1271,13 +1365,6 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
area->full = NULL;
- if (fullsa == NULL) {
- if (G.debug & G_DEBUG) {
- printf("%s: something wrong in areafullscreen\n", __func__);
- }
- return NULL;
- }
-
if (state == SCREENFULL) {
/* unhide global areas */
LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
@@ -1289,14 +1376,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
}
}
- ED_area_data_swap(fullsa, area);
+ if (fullsa) {
+ ED_area_data_swap(fullsa, area);
+ ED_area_tag_refresh(fullsa);
+ }
/* animtimer back */
screen->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
ED_screen_change(C, screen);
- ED_area_tag_refresh(fullsa);
BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
@@ -1307,68 +1396,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
screen->skip_handling = true;
}
else {
- /* change from SCREENNORMAL to new state */
- WorkSpaceLayout *layout_new;
- ScrArea *newa;
- char newname[MAX_ID_NAME - 2];
-
- BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL));
-
- bScreen *oldscreen = WM_window_get_active_screen(win);
-
- oldscreen->state = state;
- BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
-
- layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
-
- screen = BKE_workspace_layout_screen_get(layout_new);
- screen->state = state;
- screen->redraws_flag = oldscreen->redraws_flag;
- screen->temp = oldscreen->temp;
- screen->flag = oldscreen->flag;
-
- /* timer */
- screen->animtimer = oldscreen->animtimer;
- oldscreen->animtimer = NULL;
+ ScrArea *toggle_area = area;
/* use random area when we have no active one, e.g. when the
* mouse is outside of the window and we open a file browser */
- if (!area || area->global) {
- area = oldscreen->areabase.first;
+ if (!toggle_area || toggle_area->global) {
+ bScreen *oldscreen = WM_window_get_active_screen(win);
+ toggle_area = oldscreen->areabase.first;
}
- newa = (ScrArea *)screen->areabase.first;
-
- /* copy area */
- ED_area_data_swap(newa, area);
- newa->flag = area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
-
- if (state == SCREENFULL) {
- /* temporarily hide global areas */
- LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
- glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
- }
- /* temporarily hide the side panels/header */
- LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) {
- region->flagfullscreen = region->flag;
-
- if (ELEM(region->regiontype,
- RGN_TYPE_UI,
- RGN_TYPE_HEADER,
- RGN_TYPE_TOOL_HEADER,
- RGN_TYPE_FOOTER,
- RGN_TYPE_TOOLS,
- RGN_TYPE_NAV_BAR,
- RGN_TYPE_EXECUTE)) {
- region->flag |= RGN_FLAG_HIDDEN;
- }
- }
- }
-
- area->full = oldscreen;
- newa->full = oldscreen;
-
- ED_screen_change(C, screen);
+ screen = screen_state_to_nonnormal(C, win, toggle_area, state);
}
/* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
@@ -1412,9 +1449,6 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
- else if (ctx_area != NULL && ctx_area->spacetype == space_type) {
- area = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_area, SCREENMAXIMIZED);
- }
else {
area = ED_screen_full_newspace(C, ctx_area, (int)space_type);
((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index a0c5762c73c..51687d5de1d 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -5511,6 +5511,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(ED_OT_flush_edits);
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
+ WM_operatortype_append(ED_OT_lib_id_generate_preview);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 9bf3d2610d8..fff8d27ef5b 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC
../../windowmanager
../../../../intern/atomic
../../../../intern/clog
+ ../../../../intern/eigen
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 175d98ba9aa..3ca0d853d6a 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -43,7 +43,6 @@ struct wmEvent;
struct wmKeyConfig;
struct wmOperator;
struct wmOperatorType;
-struct wmWindowManager;
enum ePaintMode;
enum ePaintSymmetryFlags;
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 17690757fa5..92c78a674f0 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1552,6 +1552,11 @@ static int sculpt_trim_gesture_box_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (ss->totvert == 0) {
+ /* No geometry to trim or to detect a valid position for the trimming shape. */
+ return OPERATOR_CANCELLED;
+ }
+
SculptGestureContext *sgcontext = sculpt_gesture_init_from_box(C, op);
if (!sgcontext) {
return OPERATOR_CANCELLED;
@@ -1589,6 +1594,11 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (ss->totvert == 0) {
+ /* No geometry to trim or to detect a valid position for the trimming shape. */
+ return OPERATOR_CANCELLED;
+ }
+
SculptGestureContext *sgcontext = sculpt_gesture_init_from_lasso(C, op);
if (!sgcontext) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 94f05560f79..38d2bed7d97 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1227,6 +1227,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
SCULPT_TOOL_SMOOTH,
SCULPT_TOOL_LAYER,
SCULPT_TOOL_POSE,
+ SCULPT_TOOL_DISPLACEMENT_SMEAR,
SCULPT_TOOL_BOUNDARY,
SCULPT_TOOL_CLOTH,
SCULPT_TOOL_PAINT,
@@ -2362,6 +2363,7 @@ static float brush_strength(const Sculpt *sd,
final_pressure = pressure * pressure;
return final_pressure * overlap * feather;
case SCULPT_TOOL_SMEAR:
+ case SCULPT_TOOL_DISPLACEMENT_SMEAR:
return alpha * pressure * overlap * feather;
case SCULPT_TOOL_CLAY_STRIPS:
/* Clay Strips needs less strength to compensate the curve. */
@@ -3103,6 +3105,147 @@ static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **node
/** \} */
+/** \name Sculpt Multires Displacement Smear Brush
+ * \{ */
+
+static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float current_disp[3];
+ float current_disp_norm[3];
+ float interp_limit_surface_disp[3];
+
+ copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
+
+ switch (brush->smear_deform_type) {
+ case BRUSH_SMEAR_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SMEAR_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SMEAR_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ float weights_accum = 1.0f;
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ float neighbor_limit_co[3];
+ SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
+ sub_v3_v3v3(vertex_disp,
+ ss->cache->limit_surface_co[ni.index],
+ ss->cache->limit_surface_co[vd.index]);
+ const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) < 0.0f) {
+ const float disp_interp = clamp_f(
+ -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
+ madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
+ weights_accum += disp_interp;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
+
+ float new_co[3];
+ add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
+ interp_v3_v3v3(vd.co, vd.co, new_co, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_displacement_smear_store_prev_disp_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
+ SCULPT_vertex_co_get(ss, vd.index),
+ ss->cache->limit_surface_co[vd.index]);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_curvemapping_init(brush->curve);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ if (!ss->cache->prev_displacement) {
+ ss->cache->prev_displacement = MEM_malloc_arrayN(
+ totvert, sizeof(float[3]), "prev displacement");
+ ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
+ for (int i = 0; i < totvert; i++) {
+ SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
+ sub_v3_v3v3(ss->cache->prev_displacement[i],
+ SCULPT_vertex_co_get(ss, i),
+ ss->cache->limit_surface_co[i]);
+ }
+ }
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
static void do_draw_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -5742,32 +5885,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
}
else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
- if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_LOCAL) {
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)),
- .original = false,
- .ignore_fully_ineffective = false,
- .center = ss->cache->initial_location,
- };
- BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
- }
- if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC) {
- SculptSearchSphereData data = {
- .ss = ss,
- .sd = sd,
- .radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)),
- .original = false,
- .ignore_fully_ineffective = false,
- .center = ss->cache->location,
- };
- BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
- }
- else {
- /* Gobal simulation, get all nodes. */
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- }
+ nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode);
}
else {
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
@@ -5805,6 +5923,17 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
}
+ /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with
+ * zero radius, thus we have no pbvh nodes on the first brush step. */
+ if (totnode ||
+ ((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) {
+ if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
+ if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob);
+ }
+ }
+ }
+
/* Only act if some verts are inside the brush area. */
if (totnode) {
float location[3];
@@ -5828,12 +5957,6 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
update_brush_local_mat(sd, ob);
}
- if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
- if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
- ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob);
- }
- }
-
if (brush->sculpt_tool == SCULPT_TOOL_POSE && SCULPT_stroke_is_first_brush_step(ss->cache)) {
SCULPT_pose_brush_init(sd, ob, ss, brush);
}
@@ -5952,6 +6075,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
case SCULPT_TOOL_DISPLACEMENT_ERASER:
do_displacement_eraser_brush(sd, ob, nodes, totnode);
break;
+ case SCULPT_TOOL_DISPLACEMENT_SMEAR:
+ do_displacement_smear_brush(sd, ob, nodes, totnode);
+ break;
case SCULPT_TOOL_PAINT:
SCULPT_do_paint_brush(sd, ob, nodes, totnode);
break;
@@ -6515,6 +6641,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Draw Face Sets";
case SCULPT_TOOL_DISPLACEMENT_ERASER:
return "Multires Displacement Eraser";
+ case SCULPT_TOOL_DISPLACEMENT_SMEAR:
+ return "Multires Displacement Smear";
case SCULPT_TOOL_PAINT:
return "Paint Brush";
case SCULPT_TOOL_SMEAR:
@@ -6535,6 +6663,8 @@ void SCULPT_cache_free(StrokeCache *cache)
MEM_SAFE_FREE(cache->layer_displacement_factor);
MEM_SAFE_FREE(cache->prev_colors);
MEM_SAFE_FREE(cache->detail_directions);
+ MEM_SAFE_FREE(cache->prev_displacement);
+ MEM_SAFE_FREE(cache->limit_surface_co);
if (cache->pose_ik_chain) {
SCULPT_pose_ik_chain_free(cache->pose_ik_chain);
@@ -6706,6 +6836,7 @@ static void sculpt_update_cache_invariants(
SCULPT_TOOL_MASK,
SCULPT_TOOL_SMOOTH,
SCULPT_TOOL_SIMPLIFY,
+ SCULPT_TOOL_DISPLACEMENT_SMEAR,
SCULPT_TOOL_DISPLACEMENT_ERASER) &&
(sd->gravity_factor > 0.0f));
/* Get gravity vector in world space. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index f8165890cc4..0ac0d796ca4 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -119,6 +119,43 @@ static void cloth_brush_simulation_location_get(SculptSession *ss,
copy_v3_v3(r_location, ss->cache->location);
}
+PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
+ Brush *brush,
+ int *r_totnode)
+{
+ BLI_assert(ss->cache);
+ BLI_assert(brush->sculpt_tool == SCULPT_TOOL_CLOTH);
+ PBVHNode **nodes = NULL;
+
+ switch (brush->cloth_simulation_area_type) {
+ case BRUSH_CLOTH_SIMULATION_AREA_LOCAL: {
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)),
+ .original = false,
+ .ignore_fully_ineffective = false,
+ .center = ss->cache->initial_location,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
+ } break;
+ case BRUSH_CLOTH_SIMULATION_AREA_GLOBAL:
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, r_totnode);
+ break;
+ case BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC: {
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)),
+ .original = false,
+ .ignore_fully_ineffective = false,
+ .center = ss->cache->location,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
+ } break;
+ }
+
+ return nodes;
+}
+
static float cloth_brush_simulation_falloff_get(const Brush *brush,
const float radius,
const float location[3],
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index ad42750bb92..1fba958d695 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -41,6 +41,7 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_fair.h"
#include "BKE_mesh_mapping.h"
#include "BKE_multires.h"
#include "BKE_node.h"
@@ -1024,6 +1025,8 @@ typedef enum eSculptFaceSetEditMode {
SCULPT_FACE_SET_EDIT_GROW = 0,
SCULPT_FACE_SET_EDIT_SHRINK = 1,
SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY = 2,
+ SCULPT_FACE_SET_EDIT_FAIR_POSITIONS = 3,
+ SCULPT_FACE_SET_EDIT_FAIR_TANGENCY = 4,
} eSculptFaceSetEditMode;
static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = {
@@ -1048,6 +1051,22 @@ static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = {
"Delete Geometry",
"Deletes the faces that are assigned to the Face Set",
},
+ {
+ SCULPT_FACE_SET_EDIT_FAIR_POSITIONS,
+ "FAIR_POSITIONS",
+ 0,
+ "Fair Positions",
+ "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
+ "vertex positions",
+ },
+ {
+ SCULPT_FACE_SET_EDIT_FAIR_TANGENCY,
+ "FAIR_TANGENCY",
+ 0,
+ "Fair Tangency",
+ "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
+ "vertex tangents",
+ },
{0, NULL, 0, NULL, NULL},
};
@@ -1181,6 +1200,29 @@ static void sculpt_face_set_delete_geometry(Object *ob,
BM_mesh_free(bm);
}
+static void sculpt_face_set_edit_fair_face_set(Object *ob,
+ const int active_face_set_id,
+ const int fair_order)
+{
+ SculptSession *ss = ob->sculpt;
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ Mesh *mesh = ob->data;
+ bool *fair_vertices = MEM_malloc_arrayN(sizeof(bool), totvert, "fair vertices");
+
+ SCULPT_boundary_info_ensure(ob);
+
+ for (int i = 0; i < totvert; i++) {
+ fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, i) &&
+ SCULPT_vertex_has_face_set(ss, i, active_face_set_id) &&
+ SCULPT_vertex_has_unique_face_set(ss, i);
+ }
+
+ MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
+ BKE_mesh_prefair_and_fair_vertices(mesh, mvert, fair_vertices, fair_order);
+ MEM_freeN(fair_vertices);
+}
+
static void sculpt_face_set_apply_edit(Object *ob,
const int active_face_set_id,
const int mode,
@@ -1204,6 +1246,12 @@ static void sculpt_face_set_apply_edit(Object *ob,
case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY:
sculpt_face_set_delete_geometry(ob, ss, active_face_set_id, modify_hidden);
break;
+ case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS:
+ sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_POSITION);
+ break;
+ case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY:
+ sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_TANGENCY);
+ break;
}
}
@@ -1230,6 +1278,16 @@ static bool sculpt_face_set_edit_is_operation_valid(SculptSession *ss,
return false;
}
}
+
+ if (ELEM(mode, SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, SCULPT_FACE_SET_EDIT_FAIR_TANGENCY)) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ /* TODO: Multires topology representation using grids and duplicates can't be used directly
+ * by the fair algorithm. Multires topology needs to be exposed in a different way or
+ * converted to a mesh for this operation. */
+ return false;
+ }
+ }
+
return true;
}
@@ -1287,11 +1345,38 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob,
MEM_freeN(nodes);
}
+static void sculpt_face_set_edit_modify_coordinates(bContext *C,
+ Object *ob,
+ const int active_face_set,
+ const eSculptFaceSetEditMode mode)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ss->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SCULPT_undo_push_begin(ob, "face set edit");
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_update(nodes[i]);
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS);
+ }
+ sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, false);
+
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
+ SCULPT_flush_stroke_deform(sd, ob, true);
+ }
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ SCULPT_undo_push_end();
+ MEM_freeN(nodes);
+}
+
static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
const int mode = RNA_enum_get(op->ptr, "mode");
const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden");
@@ -1320,6 +1405,10 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven
case SCULPT_FACE_SET_EDIT_SHRINK:
sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden);
break;
+ case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS:
+ case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY:
+ sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode);
+ break;
}
SCULPT_tag_update_overlays(C);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index e0d413bc75f..d1e17c7e59b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -39,7 +39,6 @@
struct AutomaskingCache;
struct KeyBlock;
struct Object;
-struct SculptPoseIKChainSegment;
struct SculptUndoNode;
struct bContext;
@@ -423,6 +422,10 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
const float outline_col[3],
float outline_alpha);
+PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
+ Brush *brush,
+ int *r_totnode);
+
BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
{
return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type,
@@ -923,6 +926,10 @@ typedef struct StrokeCache {
float (*prev_colors)[4];
+ /* Multires Displacement Smear. */
+ float (*prev_displacement)[3];
+ float (*limit_surface_co)[3];
+
/* The rest is temporary storage that isn't saved as a property */
bool first_time; /* Beginning of stroke may do some things special */
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 3a2b8cf0115..c1f29231f96 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -826,6 +826,11 @@ int /*eContextResult*/ buttons_context(const bContext *C,
bContextDataResult *result)
{
SpaceProperties *sbuts = CTX_wm_space_properties(C);
+ if (sbuts && sbuts->path == NULL) {
+ /* path is cleared for SCREEN_OT_redo_last, when global undo does a file-read which clears the
+ * path (see lib_link_workspace_layout_restore). */
+ buttons_context_compute(C, sbuts);
+ }
ButsContextPath *path = sbuts ? sbuts->path : NULL;
if (!path) {
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 0a0846cf216..74e7bc11c26 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -35,7 +35,6 @@ struct bContext;
struct bContextDataResult;
struct bNode;
struct bNodeTree;
-struct uiLayout;
struct wmOperatorType;
struct SpaceProperties_Runtime {
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index afa1fa0edee..d66219c7549 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1178,7 +1178,7 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
return filelist_geticon_image_ex(file);
}
-static int filelist_geticon_ex(FileDirEntry *file,
+static int filelist_geticon_ex(const FileDirEntry *file,
const char *root,
const bool is_main,
const bool ignore_libdir)
@@ -1217,7 +1217,7 @@ static int filelist_geticon_ex(FileDirEntry *file,
if (file->redirection_path) {
target = file->redirection_path;
}
- else {
+ else if (root) {
BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
BLI_path_slash_ensure(fullpath);
}
@@ -1301,6 +1301,12 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
return filelist_geticon_ex(file, filelist->filelist.root, is_main, false);
}
+int ED_file_icon(const FileDirEntry *file)
+{
+ return file->preview_icon_id ? file->preview_icon_id :
+ filelist_geticon_ex(file, NULL, false, false);
+}
+
/* ********** Main ********** */
static void parent_dir_until_exists_or_default_root(char *dir)
@@ -1511,7 +1517,9 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
* in case user switch to a bigger preview size. */
ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
IMB_thumb_path_unlock(preview->path);
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ }
done = true;
}
@@ -3450,22 +3458,21 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
return;
}
- else {
- /* setup job */
- wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- CTX_data_scene(C),
- "Listing Dirs...",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_FILESEL_READDIR);
- WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free);
- WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST);
- WM_jobs_callbacks(
- wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob);
-
- /* start the job */
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- }
+
+ /* setup job */
+ wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ CTX_data_scene(C),
+ "Listing Dirs...",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_FILESEL_READDIR);
+ WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free);
+ WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST);
+ WM_jobs_callbacks(
+ wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob);
+
+ /* start the job */
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
}
void filelist_readjob_stop(wmWindowManager *wm, Scene *owner_scene)
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 59bd5bb50d7..16984bb6e43 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -29,8 +29,8 @@ extern "C" {
struct BlendHandle;
struct FileList;
-struct FileSelection;
struct FileSelectAssetLibraryUID;
+struct FileSelection;
struct wmWindowManager;
struct FileDirEntry;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index cd27b7b5773..b919a30e6cd 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -490,7 +490,7 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
wmOperator *op = sfile->op;
UserDef_FileSpaceData *sfile_udata = &U.file_space_data;
- BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_FILES);
+ sfile->browse_mode = FILE_BROWSE_MODE_FILES;
FileSelectParams *params = fileselect_ensure_updated_file_params(sfile);
if (!op) {
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 09b7e5b348c..774dc54700c 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -779,7 +779,7 @@ static void file_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_file_browse_mode_items);
}
-const char *file_context_dir[] = {"active_file", "active_id", NULL};
+static const char *file_context_dir[] = {"active_file", "active_id", NULL};
static int /*eContextResult*/ file_context(const bContext *C,
const char *member,
@@ -803,16 +803,25 @@ static int /*eContextResult*/ file_context(const bContext *C,
if (CTX_data_equals(member, "active_file")) {
FileDirEntry *file = filelist_file(sfile->files, params->active_file);
+ if (file == NULL) {
+ return CTX_RESULT_NO_DATA;
+ }
+
CTX_data_pointer_set(result, &screen->id, &RNA_FileSelectEntry, file);
return CTX_RESULT_OK;
}
- if (CTX_data_equals(member, "active_id")) {
+ if (CTX_data_equals(member, "id")) {
const FileDirEntry *file = filelist_file(sfile->files, params->active_file);
+ if (file == NULL) {
+ return CTX_RESULT_NO_DATA;
+ }
ID *id = filelist_file_get_id(file);
- if (id) {
- CTX_data_id_pointer_set(result, id);
+ if (id == NULL) {
+ return CTX_RESULT_NO_DATA;
}
+
+ CTX_data_id_pointer_set(result, id);
return CTX_RESULT_OK;
}
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index f8c71791054..45f3b6cf9c9 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -3208,6 +3208,20 @@ static void node_geometry_buts_attribute_mix(uiLayout *layout,
uiItemR(col, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("B"), ICON_NONE);
}
+static void node_geometry_buts_attribute_point_distribute(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distribute_method", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_geometry_buts_attribute_color_ramp(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiTemplateColorRamp(layout, ptr, "color_ramp", 0);
+}
+
static void node_geometry_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
@@ -3220,7 +3234,7 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
case GEO_NODE_TRIANGULATE:
ntype->draw_buttons = node_geometry_buts_triangulate;
break;
- case GEO_NODE_RANDOM_ATTRIBUTE:
+ case GEO_NODE_ATTRIBUTE_RANDOMIZE:
ntype->draw_buttons = node_geometry_buts_random_attribute;
break;
case GEO_NODE_ATTRIBUTE_MATH:
@@ -3235,6 +3249,12 @@ static void node_geometry_set_butfunc(bNodeType *ntype)
case GEO_NODE_ATTRIBUTE_MIX:
ntype->draw_buttons = node_geometry_buts_attribute_mix;
break;
+ case GEO_NODE_POINT_DISTRIBUTE:
+ ntype->draw_buttons = node_geometry_buts_attribute_point_distribute;
+ break;
+ case GEO_NODE_ATTRIBUTE_COLOR_RAMP:
+ ntype->draw_buttons = node_geometry_buts_attribute_color_ramp;
+ break;
}
}
diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c
index e7dc2780c37..a314a640e42 100644
--- a/source/blender/editors/space_outliner/outliner_context.c
+++ b/source/blender/editors/space_outliner/outliner_context.c
@@ -50,7 +50,7 @@ static void outliner_context_selected_ids(const SpaceOutliner *space_outliner,
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
}
-const char *outliner_context_dir[] = {"selected_ids", NULL};
+static const char *outliner_context_dir[] = {"selected_ids", NULL};
int /*eContextResult*/ outliner_context(const bContext *C,
const char *member,
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index ccb481197e4..339cc3068d0 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -32,7 +32,6 @@ extern "C" {
/* internal exports only */
struct ARegion;
-struct bContextDataResult;
struct EditBone;
struct ID;
struct ListBase;
@@ -43,6 +42,7 @@ struct TreeElement;
struct TreeStoreElem;
struct ViewLayer;
struct bContext;
+struct bContextDataResult;
struct bPoseChannel;
struct wmKeyConfig;
struct wmOperatorType;
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index e4c3ebfdff5..492fc5c23bc 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -737,7 +737,7 @@ static void id_local_fn(bContext *C,
}
static void object_proxy_to_override_convert_fn(bContext *C,
- ReportList *UNUSED(reports),
+ ReportList *reports,
Scene *UNUSED(scene),
TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep),
@@ -754,8 +754,15 @@ static void object_proxy_to_override_convert_fn(bContext *C,
return;
}
- BKE_lib_override_library_proxy_convert(
- CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy);
+ if (!BKE_lib_override_library_proxy_convert(
+ CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy)) {
+ BKE_reportf(
+ reports,
+ RPT_ERROR_INVALID_INPUT,
+ "Could not create a library override from proxy '%s' (might use already local data?)",
+ ob_proxy->id.name + 2);
+ return;
+ }
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_WINDOW, NULL);
diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.hh b/source/blender/editors/space_outliner/tree/tree_element_nla.hh
index 3ca62b13bd8..c94287ce576 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_nla.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_nla.hh
@@ -23,7 +23,6 @@
#include "tree_element.hh"
struct NlaTrack;
-struct NlaStrip;
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 37dfcdbc765..71433a6978a 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -81,9 +81,18 @@ typedef struct SequencerAddData {
#define SEQPROP_ENDFRAME (1 << 1)
#define SEQPROP_NOPATHS (1 << 2)
#define SEQPROP_NOCHAN (1 << 3)
+#define SEQPROP_FIT_METHOD (1 << 4)
#define SELECT 1
+static const EnumPropertyItem scale_fit_methods[] = {
+ {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"},
+ {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"},
+ {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image to fill the canvas"},
+ {SEQ_USE_ORIGINAL_SIZE, "ORIGINAL", 0, "Use Original Size", "Keep image at its original size"},
+ {0, NULL, 0, NULL, NULL},
+};
+
static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
{
PropertyRNA *prop;
@@ -123,6 +132,15 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
prop = RNA_def_boolean(
ot->srna, "overlap", 0, "Allow Overlap", "Don't correct overlap on new sequence strips");
RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ if (flag & SEQPROP_FIT_METHOD) {
+ ot->prop = RNA_def_enum(ot->srna,
+ "fit_method",
+ scale_fit_methods,
+ SEQ_SCALE_TO_FIT,
+ "Fit Method",
+ "Scale fit method");
+ }
}
static void sequencer_generic_invoke_path__internal(bContext *C,
@@ -206,6 +224,8 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
seq_load->end_frame = seq_load->start_frame;
seq_load->channel = RNA_int_get(op->ptr, "channel");
seq_load->len = 1;
+ seq_load->fit_method = RNA_enum_get(op->ptr, "fit_method");
+ SEQ_tool_settings_fit_method_set(CTX_data_scene(C), seq_load->fit_method);
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
/* Full path, file is set by the caller. */
@@ -659,6 +679,7 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
if (ed && ed->seqbasep && ed->seqbasep->first) {
RNA_boolean_set(op->ptr, "use_framerate", false);
}
+ RNA_enum_set(op->ptr, "fit_method", SEQ_tool_settings_fit_method_get(scene));
/* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
@@ -725,7 +746,7 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
- sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
+ sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_FIT_METHOD);
RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie");
RNA_def_boolean(ot->srna,
"use_framerate",
@@ -928,6 +949,9 @@ static int sequencer_add_image_strip_invoke(bContext *C,
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
+ const SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings;
+ RNA_enum_set(op->ptr, "fit_method", tool_settings->fit_method);
+
/* Name set already by drag and drop. */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(
@@ -972,7 +996,8 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
- sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
+ sequencer_generic_props__internal(ot,
+ SEQPROP_STARTFRAME | SEQPROP_ENDFRAME | SEQPROP_FIT_METHOD);
RNA_def_boolean(ot->srna,
"use_placeholders",
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 081714991ff..d7d601a3c76 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -227,16 +227,16 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, uchar col[3])
* \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2.
* \param stepsize: The width of a pixel.
*/
-static void draw_seq_waveform(View2D *v2d,
- const bContext *C,
- SpaceSeq *sseq,
- Scene *scene,
- Sequence *seq,
- float x1,
- float y1,
- float x2,
- float y2,
- float stepsize)
+static void draw_seq_waveform_overlay(View2D *v2d,
+ const bContext *C,
+ SpaceSeq *sseq,
+ Scene *scene,
+ Sequence *seq,
+ float x1,
+ float y1,
+ float x2,
+ float y2,
+ float stepsize)
{
/* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
int x1_offset = max_ff(v2d->cur.xmin, x1);
@@ -603,121 +603,110 @@ static void draw_seq_outline(Sequence *seq,
}
}
-/* Draw info text on a sequence strip. */
-static void draw_seq_text(View2D *v2d,
- Sequence *seq,
- SpaceSeq *sseq,
- float x1,
- float x2,
- float y1,
- float y2,
- bool seq_active,
- bool y_threshold)
+static const char *draw_seq_text_get_name(Sequence *seq)
{
- rctf rect;
- char str[32 + FILE_MAX];
- size_t str_len;
const char *name = seq->name + 2;
- uchar col[4];
-
- /* All strings should include name. */
if (name[0] == '\0') {
name = BKE_sequence_give_name(seq);
}
+ return name;
+}
- if (ELEM(seq->type, SEQ_TYPE_META, SEQ_TYPE_ADJUSTMENT)) {
- str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
+static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t source_len)
+{
+ /* Set source for the most common types. */
+ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
+ BLI_snprintf(r_source, source_len, "%s%s", seq->strip->dir, seq->strip->stripdata->name);
}
- else if (seq->type == SEQ_TYPE_SCENE) {
- if (seq->scene) {
- if (seq->scene_camera) {
- str_len = BLI_snprintf(str,
- sizeof(str),
- "%s: %s (%s) | %d",
- name,
- seq->scene->id.name + 2,
- ((ID *)seq->scene_camera)->name + 2,
- seq->len);
- }
- else {
- str_len = BLI_snprintf(
- str, sizeof(str), "%s: %s | %d", name, seq->scene->id.name + 2, seq->len);
- }
- }
- else {
- str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
+ else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ if (seq->sound) {
+ BLI_snprintf(r_source, source_len, "%s", seq->sound->filepath);
}
}
- else if (seq->type == SEQ_TYPE_MOVIECLIP) {
- if (seq->clip && !STREQ(name, seq->clip->id.name + 2)) {
- str_len = BLI_snprintf(
- str, sizeof(str), "%s: %s | %d", name, seq->clip->id.name + 2, seq->len);
- }
- else {
- str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
- }
+ else if (seq->type == SEQ_TYPE_MULTICAM) {
+ BLI_snprintf(r_source, source_len, "Channel: %d", seq->multicam_source);
}
- else if (seq->type == SEQ_TYPE_MASK) {
- if (seq->mask && !STREQ(name, seq->mask->id.name + 2)) {
- str_len = BLI_snprintf(
- str, sizeof(str), "%s: %s | %d", name, seq->mask->id.name + 2, seq->len);
+ else if (seq->type == SEQ_TYPE_TEXT) {
+ TextVars *textdata = seq->effectdata;
+ BLI_snprintf(r_source, source_len, "%s", textdata->text);
+ }
+ else if (seq->type == SEQ_TYPE_SCENE) {
+ if (seq->scene_camera) {
+ BLI_snprintf(r_source,
+ source_len,
+ "%s (%s)",
+ seq->scene->id.name + 2,
+ ((ID *)seq->scene_camera)->name + 2);
}
else {
- str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
+ BLI_snprintf(r_source, source_len, "%s", seq->scene->id.name + 2);
}
}
- else if (seq->type == SEQ_TYPE_MULTICAM) {
- str_len = BLI_snprintf(str, sizeof(str), "Cam %s: %d", name, seq->multicam_source);
- }
- else if (seq->type == SEQ_TYPE_IMAGE) {
- str_len = BLI_snprintf(str,
- sizeof(str),
- "%s: %s%s | %d",
- name,
- seq->strip->dir,
- seq->strip->stripdata->name,
- seq->len);
+ else if (seq->type == SEQ_TYPE_MOVIECLIP) {
+ BLI_snprintf(r_source, source_len, "%s", seq->clip->id.name + 2);
}
- else if (seq->type == SEQ_TYPE_TEXT) {
- TextVars *textdata = seq->effectdata;
- str_len = BLI_snprintf(str, sizeof(str), "%s | %d", textdata->text, seq->startdisp);
+ else if (seq->type == SEQ_TYPE_MASK) {
+ BLI_snprintf(r_source, source_len, "%s", seq->mask->id.name + 2);
}
- else if (seq->type & SEQ_TYPE_EFFECT) {
- str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
+ else {
+ *r_source = '\0';
}
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- /* If a waveform is drawn, avoid to draw text when there is not enough vertical space. */
- if (!y_threshold && (sseq->flag & SEQ_NO_WAVEFORMS) == 0 &&
- ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) {
+}
- str[0] = 0;
- str_len = 0;
- }
- else if (seq->sound) {
- str_len = BLI_snprintf(
- str, sizeof(str), "%s: %s | %d", name, seq->sound->filepath, seq->len);
+static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq,
+ Sequence *seq,
+ char *r_overlay_string,
+ size_t overlay_string_len)
+{
+ const char *name = draw_seq_text_get_name(seq);
+ char source[FILE_MAX];
+ int strip_duration = seq->enddisp - seq->startdisp;
+ draw_seq_text_get_source(seq, source, sizeof(source));
+
+ bool show_name = sseq->flag & SEQ_SHOW_STRIP_NAME;
+ bool show_source = (sseq->flag & (SEQ_SHOW_STRIP_SOURCE)) && source[0] != '\0';
+ bool show_duration = sseq->flag & SEQ_SHOW_STRIP_DURATION;
+
+ size_t string_len = 0;
+ if (show_name) {
+ string_len = BLI_snprintf(r_overlay_string, overlay_string_len, "%s", name);
+ if (show_source || show_duration) {
+ string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, " | ");
}
- else {
- str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
+ }
+ if (show_source) {
+ string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, "%s", source);
+ if (show_duration) {
+ string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, " | ");
}
}
- else if (seq->type == SEQ_TYPE_MOVIE) {
- str_len = BLI_snprintf(str,
- sizeof(str),
- "%s: %s%s | %d",
- name,
- seq->strip->dir,
- seq->strip->stripdata->name,
- seq->len);
+ if (show_duration) {
+ string_len += BLI_snprintf(
+ r_overlay_string + string_len, overlay_string_len, "%d", strip_duration);
}
- else {
- /* Should never get here!, but might with files from future. */
- BLI_assert(0);
+ return string_len;
+}
+
+/* Draw info text on a sequence strip. */
+static void draw_seq_text_overlay(View2D *v2d,
+ Sequence *seq,
+ SpaceSeq *sseq,
+ float x1,
+ float x2,
+ float y1,
+ float y2,
+ bool seq_active)
+{
+ char overlay_string[FILE_MAX];
+ size_t overlay_string_len = draw_seq_text_get_overlay_string(
+ sseq, seq, overlay_string, sizeof(overlay_string));
- str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
+ if (overlay_string_len == 0) {
+ return;
}
/* White text for the active strip. */
+ uchar col[4];
col[0] = col[1] = col[2] = seq_active ? 255 : 10;
col[3] = 255;
@@ -731,15 +720,16 @@ static void draw_seq_text(View2D *v2d,
}
}
+ rctf rect;
rect.xmin = x1;
rect.ymin = y1;
rect.xmax = x2;
rect.ymax = y2;
- UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
+ UI_view2d_text_cache_add_rectf(v2d, &rect, overlay_string, overlay_string_len, col);
}
-static void draw_sequence_extensions(Scene *scene, Sequence *seq, uint pos, float pixely)
+static void draw_sequence_extensions_overlay(Scene *scene, Sequence *seq, uint pos, float pixely)
{
float x1, x2, y1, y2;
uchar col[4], blend_col[3];
@@ -988,7 +978,7 @@ static void fcurve_batch_add_verts(GPUVertBuf *vbo,
* - Volume for sound strips.
* - Opacity for the other types.
*/
-static void draw_seq_fcurve(
+static void draw_seq_fcurve_overlay(
Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, float pixelx)
{
FCurve *fcu;
@@ -1085,11 +1075,21 @@ static void draw_seq_strip(const bContext *C,
x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
- /* Calculate height needed for drawing text on strip. */
- float text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely);
+ float text_margin_y;
+ bool y_threshold;
+ if ((sseq->flag & SEQ_SHOW_STRIP_NAME) || (sseq->flag & SEQ_SHOW_STRIP_SOURCE) ||
+ (sseq->flag & SEQ_SHOW_STRIP_DURATION)) {
- /* Is there enough space for drawing something else than text? */
- bool y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac;
+ /* Calculate height needed for drawing text on strip. */
+ text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely);
+
+ /* Is there enough space for drawing something else than text? */
+ y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac;
+ }
+ else {
+ text_margin_y = y2;
+ y_threshold = 1;
+ }
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -1102,12 +1102,13 @@ static void draw_seq_strip(const bContext *C,
}
/* Draw strip offsets when flag is enabled or during "solo preview". */
- if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) {
- if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) {
- draw_sequence_extensions(scene, seq, pos, pixely);
+ if ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) {
+ if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) {
+ if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) {
+ draw_sequence_extensions_overlay(scene, seq, pos, pixely);
+ }
}
}
-
immUnbindProgram();
x1 = seq->startdisp;
@@ -1118,24 +1119,24 @@ static void draw_seq_strip(const bContext *C,
drawmeta_contents(scene, seq, x1, y1, x2, y2);
}
- if (sseq->flag & SEQ_SHOW_FCURVES) {
- draw_seq_fcurve(scene, v2d, seq, x1, y1, x2, y2, pixelx);
+ if ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY) && (sseq->flag & SEQ_SHOW_FCURVES)) {
+ draw_seq_fcurve_overlay(scene, v2d, seq, x1, y1, x2, y2, pixelx);
}
/* Draw sound strip waveform. */
- if ((seq->type == SEQ_TYPE_SOUND_RAM) && (sseq->flag & SEQ_NO_WAVEFORMS) == 0) {
- draw_seq_waveform(v2d,
- C,
- sseq,
- scene,
- seq,
- x1,
- y_threshold ? y1 + 0.05f : y1,
- x2,
- y_threshold ? text_margin_y : y2,
- BLI_rctf_size_x(&region->v2d.cur) / region->winx);
+ if ((seq->type == SEQ_TYPE_SOUND_RAM) && ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) &&
+ (sseq->flag & SEQ_NO_WAVEFORMS) == 0) {
+ draw_seq_waveform_overlay(v2d,
+ C,
+ sseq,
+ scene,
+ seq,
+ x1,
+ y_threshold ? y1 + 0.05f : y1,
+ x2,
+ y_threshold ? text_margin_y : y2,
+ BLI_rctf_size_x(&region->v2d.cur) / region->winx);
}
-
/* Draw locked state. */
if (seq->flag & SEQ_LOCK) {
draw_seq_locked(x1, y1, x2, y2);
@@ -1162,11 +1163,21 @@ static void draw_seq_strip(const bContext *C,
calculate_seq_text_offsets(v2d, seq, &x1, &x2, pixelx);
- /* Don't draw strip if there is not enough vertical or horizontal space. */
- if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) {
- /* Depending on the vertical space, draw text on top or in the center of strip. */
- draw_seq_text(
- v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active, y_threshold);
+ /* If a waveform is drawn, avoid drawing text when there is not enough vertical space. */
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ if (!y_threshold && (sseq->flag & SEQ_NO_WAVEFORMS) == 0 &&
+ ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) {
+ return;
+ }
+ }
+
+ if (sseq->flag & SEQ_SHOW_STRIP_OVERLAY) {
+ /* Don't draw strip if there is not enough vertical or horizontal space. */
+ if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) {
+ /* Depending on the vertical space, draw text on top or in the center of strip. */
+ draw_seq_text_overlay(
+ v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active);
+ }
}
}
@@ -1360,7 +1371,7 @@ static void sequencer_display_size(Scene *scene, float r_viewrect[2])
r_viewrect[0] *= scene->r.xasp / scene->r.yasp;
}
-static void sequencer_draw_gpencil(const bContext *C)
+static void sequencer_draw_gpencil_overlay(const bContext *C)
{
/* Draw grease-pencil (image aligned). */
ED_annotation_draw_2dimage(C);
@@ -1373,7 +1384,9 @@ static void sequencer_draw_gpencil(const bContext *C)
}
/* Draw content and safety borders borders. */
-static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene)
+static void sequencer_draw_borders_overlay(const SpaceSeq *sseq,
+ const View2D *v2d,
+ const Scene *scene)
{
float x1 = v2d->tot.xmin;
float y1 = v2d->tot.ymin;
@@ -1825,17 +1838,17 @@ void sequencer_draw_preview(const bContext *C,
C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop);
/* Draw over image. */
- if (sseq->flag & SEQ_SHOW_METADATA) {
+ if (sseq->flag & SEQ_SHOW_METADATA && sseq->flag & SEQ_SHOW_STRIP_OVERLAY) {
ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0);
}
}
- if (show_imbuf) {
- sequencer_draw_borders(sseq, v2d, scene);
+ if (show_imbuf && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) {
+ sequencer_draw_borders_overlay(sseq, v2d, scene);
}
- if (draw_gpencil && show_imbuf) {
- sequencer_draw_gpencil(C);
+ if (draw_gpencil && show_imbuf && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) {
+ sequencer_draw_gpencil_overlay(C);
}
#if 0
sequencer_draw_maskedit(C, scene, region, sseq);
@@ -2292,7 +2305,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
UI_view2d_view_ortho(v2d);
/* Get timeline bound-box, needed for the scroll-bars. */
- boundbox_seq(scene, &v2d->tot);
+ SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &v2d->tot);
draw_seq_backdrop(v2d);
UI_view2d_constant_grid_draw(v2d, FPS);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 953a77d22a6..ddc9ba2e0f6 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -183,117 +183,13 @@ bool sequencer_view_strips_poll(bContext *C)
/** \name Remove Gaps Operator
* \{ */
-static bool sequence_offset_after_frame(Scene *scene, const int delta, const int timeline_frame)
-{
- Sequence *seq;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- bool done = false;
- TimeMarker *marker;
-
- /* All strips >= timeline_frame are shifted. */
-
- if (ed == NULL) {
- return 0;
- }
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->startdisp >= timeline_frame) {
- BKE_sequence_translate(scene, seq, delta);
- BKE_sequence_calc(scene, seq);
- BKE_sequence_invalidate_cache_preprocessed(scene, seq);
- done = true;
- }
- }
-
- if (!scene->toolsettings->lock_markers) {
- for (marker = scene->markers.first; marker; marker = marker->next) {
- if (marker->frame >= timeline_frame) {
- marker->frame += delta;
- }
- }
- }
-
- return done;
-}
-
-void boundbox_seq(Scene *scene, rctf *rect)
-{
- Sequence *seq;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- float min[2], max[2];
-
- if (ed == NULL) {
- return;
- }
-
- min[0] = SFRA;
- max[0] = EFRA + 1;
- min[1] = 0.0;
- max[1] = 8.0;
-
- seq = ed->seqbasep->first;
- while (seq) {
-
- if (min[0] > seq->startdisp - 1) {
- min[0] = seq->startdisp - 1;
- }
- if (max[0] < seq->enddisp + 1) {
- max[0] = seq->enddisp + 1;
- }
- if (max[1] < seq->machine + 2) {
- max[1] = seq->machine + 2;
- }
-
- seq = seq->next;
- }
-
- rect->xmin = min[0];
- rect->xmax = max[0];
- rect->ymin = min[1];
- rect->ymax = max[1];
-}
-
static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- rctf rectf;
- int timeline_frame, efra, sfra;
- bool first = false, done;
- bool do_all = RNA_boolean_get(op->ptr, "all");
-
- /* Get first and last frame. */
- boundbox_seq(scene, &rectf);
- sfra = (int)rectf.xmin;
- efra = (int)rectf.xmax;
-
- /* Check if the current frame has a gap already. */
- for (timeline_frame = CFRA; timeline_frame >= sfra; timeline_frame--) {
- if (SEQ_render_evaluate_frame(scene, timeline_frame)) {
- first = true;
- break;
- }
- }
+ const bool do_all = RNA_boolean_get(op->ptr, "all");
+ const Editing *ed = BKE_sequencer_editing_get(scene, false);
- for (; timeline_frame < efra; timeline_frame++) {
- /* There's still no strip to remove a gap for. */
- if (first == false) {
- if (SEQ_render_evaluate_frame(scene, timeline_frame)) {
- first = true;
- }
- }
- else if (SEQ_render_evaluate_frame(scene, timeline_frame) == 0) {
- done = true;
- while (SEQ_render_evaluate_frame(scene, timeline_frame) == 0) {
- done = sequence_offset_after_frame(scene, -1, timeline_frame);
- if (done == false) {
- break;
- }
- }
- if (done == false || do_all == false) {
- break;
- }
- }
- }
+ SEQ_edit_remove_gaps(scene, ed->seqbasep, CFRA, do_all);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -330,9 +226,9 @@ void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot)
static int sequencer_gap_insert_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- int frames = RNA_int_get(op->ptr, "frames");
-
- sequence_offset_after_frame(scene, frames, CFRA);
+ const int frames = RNA_int_get(op->ptr, "frames");
+ const Editing *ed = BKE_sequencer_editing_get(scene, false);
+ SEQ_offset_after_frame(scene, ed->seqbasep, frames, CFRA);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -2631,7 +2527,7 @@ void ED_sequencer_deselect_all(Scene *scene)
SEQ_CURRENT_END;
}
-static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
+static int sequencer_paste_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -2640,8 +2536,25 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
int ofs;
Sequence *iseq, *iseq_first;
+ if (BLI_listbase_count(&seqbase_clipboard) == 0) {
+ BKE_report(op->reports, RPT_INFO, "No strips to paste");
+ return OPERATOR_CANCELLED;
+ }
+
ED_sequencer_deselect_all(scene);
- ofs = scene->r.cfra - seqbase_clipboard_frame;
+ if (RNA_boolean_get(op->ptr, "keep_offset")) {
+ ofs = scene->r.cfra - seqbase_clipboard_frame;
+ }
+ else {
+ int min_seq_startdisp = INT_MAX;
+ LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
+ if (seq->startdisp < min_seq_startdisp) {
+ min_seq_startdisp = seq->startdisp;
+ }
+ }
+ /* Paste strips after playhead. */
+ ofs = scene->r.cfra - min_seq_startdisp;
+ }
/* Copy strips, temporarily restoring pointers to actual data-blocks. This
* must happen on the clipboard itself, so that copying does user counting
@@ -2689,6 +2602,11 @@ void SEQUENCER_OT_paste(wmOperatorType *ot)
/* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties. */
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "keep_offset", false, "Keep Offset", "Keep strip offset to playhead when pasting");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -3496,3 +3414,148 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Strip Transform Operator
+ * \{ */
+
+enum {
+ STRIP_TRANSFORM_POSITION,
+ STRIP_TRANSFORM_SCALE,
+ STRIP_TRANSFORM_ROTATION,
+ STRIP_TRANSFORM_ALL,
+};
+
+static const EnumPropertyItem transform_reset_properties[] = {
+ {STRIP_TRANSFORM_POSITION, "POSITION", 0, "Position", "Reset strip transform location"},
+ {STRIP_TRANSFORM_SCALE, "SCALE", 0, "Scale", "Reset strip transform scale"},
+ {STRIP_TRANSFORM_ROTATION, "ROTATION", 0, "Rotation", "Reset strip transform rotation"},
+ {STRIP_TRANSFORM_ALL, "ALL", 0, "All", "Reset strip transform location, scale and rotation"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sequencer_strip_transform_clear_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ const Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+ const int property = RNA_enum_get(op->ptr, "property");
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) {
+ StripTransform *transform = seq->strip->transform;
+ switch (property) {
+ case STRIP_TRANSFORM_POSITION:
+ transform->xofs = 0;
+ transform->yofs = 0;
+ break;
+ case STRIP_TRANSFORM_SCALE:
+ transform->scale_x = 1.0f;
+ transform->scale_y = 1.0f;
+ break;
+ case STRIP_TRANSFORM_ROTATION:
+ transform->rotation = 0.0f;
+ break;
+ case STRIP_TRANSFORM_ALL:
+ transform->xofs = 0;
+ transform->yofs = 0;
+ transform->scale_x = 1.0f;
+ transform->scale_y = 1.0f;
+ transform->rotation = 0.0f;
+ break;
+ }
+ BKE_sequence_invalidate_cache_preprocessed(scene, seq);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Clear Strip Transform";
+ ot->idname = "SEQUENCER_OT_strip_transform_clear";
+ ot->description = "Reset image transformation to default value";
+
+ /* Api callbacks. */
+ ot->exec = sequencer_strip_transform_clear_exec;
+ ot->poll = sequencer_edit_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna,
+ "property",
+ transform_reset_properties,
+ STRIP_TRANSFORM_ALL,
+ "Property",
+ "Strip transform property to be reset");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Set Fit Operator
+ * \{ */
+
+static const EnumPropertyItem scale_fit_methods[] = {
+ {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image so fits in preview"},
+ {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image so it fills preview completely"},
+ {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image so it fills preview"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sequencer_strip_transform_fit_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ const Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+ const eSeqImageFitMethod fit_method = RNA_enum_get(op->ptr, "fit_method");
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) {
+ const int timeline_frame = CFRA;
+ StripElem *strip_elem = SEQ_render_give_stripelem(seq, timeline_frame);
+
+ if (strip_elem == NULL) {
+ continue;
+ }
+
+ SEQ_set_scale_to_fit(seq,
+ strip_elem->orig_width,
+ strip_elem->orig_height,
+ scene->r.xsch,
+ scene->r.ysch,
+ fit_method);
+ BKE_sequence_invalidate_cache_preprocessed(scene, seq);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Strip Transform Set Fit";
+ ot->idname = "SEQUENCER_OT_strip_transform_fit";
+
+ /* Api callbacks. */
+ ot->exec = sequencer_strip_transform_fit_exec;
+ ot->poll = sequencer_edit_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna,
+ "fit_method",
+ scale_fit_methods,
+ SEQ_SCALE_TO_FIT,
+ "Fit Method",
+ "Scale fit fit_method");
+}
+
+/** \} */
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 1ea4fb05d53..4c942a83f2b 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -71,7 +71,6 @@ struct ImBuf *sequencer_ibuf_get(struct Main *bmain,
/* sequencer_edit.c */
struct View2D;
void seq_rectf(struct Sequence *seq, struct rctf *rectf);
-void boundbox_seq(struct Scene *scene, struct rctf *rect);
struct Sequence *find_nearest_seq(struct Scene *scene,
struct View2D *v2d,
int *hand,
@@ -145,6 +144,8 @@ void SEQUENCER_OT_enable_proxies(struct wmOperatorType *ot);
void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot);
void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot);
+void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot);
+void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot);
/* sequencer_select.c */
void SEQUENCER_OT_select_all(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index bdf6e4ece7f..7bfc8600544 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -81,6 +81,8 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_change_path);
WM_operatortype_append(SEQUENCER_OT_set_range_to_strips);
+ WM_operatortype_append(SEQUENCER_OT_strip_transform_clear);
+ WM_operatortype_append(SEQUENCER_OT_strip_transform_fit);
/* sequencer_select.c */
WM_operatortype_append(SEQUENCER_OT_select_all);
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 75d92d5f00d..e12c43b7804 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -87,8 +87,10 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op)
rctf box;
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ Scene *scene = CTX_data_scene(C);
+ const Editing *ed = BKE_sequencer_editing_get(scene, false);
- boundbox_seq(CTX_data_scene(C), &box);
+ SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &box);
UI_view2d_smooth_view(C, region, &box, smooth_viewtx);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 45c7bac54f8..2bf4741e4f5 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -99,7 +99,8 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce
sseq->view = SEQ_VIEW_SEQUENCE;
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES |
- SEQ_ZOOM_TO_FIT;
+ SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY | SEQ_SHOW_STRIP_NAME |
+ SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_DURATION;
/* Tool header. */
region = MEM_callocN(sizeof(ARegion), "tool header for sequencer");
@@ -706,7 +707,8 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
SpaceSeq *sseq = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW));
+ const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) &&
+ (sseq->flag & SEQ_SHOW_STRIP_OVERLAY));
/* XXX temp fix for wrong setting in sseq->mainb */
if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 227330e8524..91bf2bf8aac 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -52,12 +52,12 @@ struct SnapObjectContext;
struct TransDataContainer;
struct TransInfo;
struct TransSnap;
-struct TransformOrientation;
struct ViewLayer;
struct bContext;
struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
+struct wmOperator;
struct wmTimer;
/** #TransInfo.redraw */
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index b753572ea7b..59fcd016020 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -29,12 +29,9 @@ struct FCurve;
struct ListBase;
struct Object;
struct TransData;
-struct TransDataContainer;
struct TransDataCurveHandleFlags;
struct TransInfo;
struct bContext;
-struct bKinematicConstraint;
-struct bPoseChannel;
/* transform_convert.c */
void transform_autoik_update(TransInfo *t, short mode);
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 90c1f241338..8597c372537 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -377,6 +377,9 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
else {
mul_v3_m3v3(global_dir, t->spacemtx, global_dir);
}
+ if (t->flag & T_2D_EDIT) {
+ removeAspectRatio(t, global_dir);
+ }
}
else {
copy_v3_v3(global_dir, t->values);
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index 5bee572c603..db8ec943bfd 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -25,8 +25,6 @@
/* For enum. */
#include "DNA_space_types.h"
-struct SnapObjectParams;
-
bool peelObjectsTransform(struct TransInfo *t,
const float mval[2],
const bool use_peel_object,
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 6547e42f410..d78758dcc1c 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -67,6 +67,7 @@
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_paint.h"
+#include "ED_render.h"
#include "ED_space_api.h"
#include "ED_util.h"
@@ -505,9 +506,9 @@ void ED_OT_flush_edits(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
}
-static bool lib_id_load_custom_preview_poll(bContext *C)
+static bool lib_id_preview_editing_poll(bContext *C)
{
- const PointerRNA idptr = CTX_data_pointer_get(C, "active_id");
+ const PointerRNA idptr = CTX_data_pointer_get(C, "id");
BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type));
const ID *id = idptr.data;
@@ -541,7 +542,7 @@ static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- PointerRNA idptr = CTX_data_pointer_get(C, "active_id");
+ PointerRNA idptr = CTX_data_pointer_get(C, "id");
ID *id = idptr.data;
BKE_previewimg_id_custom_set(id, path);
@@ -558,7 +559,7 @@ void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
ot->idname = "ED_OT_lib_id_load_custom_preview";
/* api callbacks */
- ot->poll = lib_id_load_custom_preview_poll;
+ ot->poll = lib_id_preview_editing_poll;
ot->exec = lib_id_load_custom_preview_exec;
ot->invoke = WM_operator_filesel;
@@ -573,3 +574,35 @@ void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
}
+
+static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA idptr = CTX_data_pointer_get(C, "id");
+ ID *id = idptr.data;
+
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+
+ PreviewImage *preview = BKE_previewimg_id_get(id);
+ if (preview) {
+ BKE_previewimg_clear(preview);
+ }
+ UI_icon_render_id(C, NULL, id, true, true);
+
+ WM_event_add_notifier(C, NC_ASSET, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ED_OT_lib_id_generate_preview(wmOperatorType *ot)
+{
+ ot->name = "Generate Preview";
+ ot->description = "Create an automatic preview for the selected data-block";
+ ot->idname = "ED_OT_lib_id_generate_preview";
+
+ /* api callbacks */
+ ot->poll = lib_id_preview_editing_poll;
+ ot->exec = lib_id_generate_preview_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_INTERNAL;
+}
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 306f8a2c561..28567234fab 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -25,7 +25,6 @@
struct BMFace;
struct BMLoop;
-struct Image;
struct Object;
struct Scene;
struct SpaceImage;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index e5a6d9e6a8f..30e54f44499 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -23,9 +23,7 @@
#pragma once
-struct GHash;
struct MDeformVert;
-struct Main;
struct Material;
struct Object;
struct bGPDlayer;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
index aa21bf192c4..b8fa88327fc 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -237,9 +237,17 @@ static void generate_geometry(GpencilModifierData *md,
/* To ensure a nice distribution, we use halton sequence and offset using the seed. */
BLI_halton_3d(primes, offset, x, r);
- for (int i = 0; i < 3; i++) {
- rand[j][i] = fmodf(r[i] * 2.0 - 1.0 + rand_offset, 1.0f);
- rand[j][i] = fmodf(sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0f);
+ if ((mmd->flag & GP_ARRAY_UNIFORM_RANDOM_SCALE) && j == 2) {
+ float rand_value;
+ rand_value = fmodf(r[0] * 2.0 - 1.0 + rand_offset, 1.0f);
+ rand_value = fmodf(sin(rand_value * 12.9898 + j * 78.233) * 43758.5453, 1.0f);
+ copy_v3_fl(rand[j], rand_value);
+ }
+ else {
+ for (int i = 0; i < 3; i++) {
+ rand[j][i] = fmodf(r[i] * 2.0 - 1.0 + rand_offset, 1.0f);
+ rand[j][i] = fmodf(sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0f);
+ }
}
}
/* Calculate Random matrix. */
@@ -425,6 +433,7 @@ static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "random_offset", 0, IFACE_("Offset"), ICON_NONE);
uiItemR(layout, ptr, "random_rotation", 0, IFACE_("Rotation"), ICON_NONE);
uiItemR(layout, ptr, "random_scale", 0, IFACE_("Scale"), ICON_NONE);
+ uiItemR(layout, ptr, "use_uniform_random_scale", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE);
}
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 27a7ea1e6a5..55716b584c3 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -27,8 +27,6 @@
extern "C" {
#endif
-struct GPUTexture;
-struct GPUUniformBuf;
struct GPUVertBuf;
/** Opaque type hidding blender::gpu::Shader */
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index e9c081abd22..91119bd05a1 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -28,14 +28,6 @@
#include "GPU_state.h"
struct GPUVertBuf;
-struct ImBuf;
-struct Image;
-struct ImageUser;
-struct MovieClip;
-struct MovieClipUser;
-struct PreviewImage;
-
-struct GPUFrameBuffer;
/** Opaque type hiding blender::gpu::Texture. */
typedef struct GPUTexture GPUTexture;
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 5d130d75d2c..f3d58a55814 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -31,10 +31,7 @@ extern "C" {
struct GPUMaterial;
struct GPUNodeGraph;
-struct GPUOutput;
struct GPUShader;
-struct GSet;
-struct ListBase;
typedef struct GPUPass {
struct GPUPass *next;
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 0ef95d94c0d..929191cff73 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -33,8 +33,6 @@
struct GPUNode;
struct GPUOutput;
-struct GPUShader;
-struct GPUVertAttrLayers;
struct ListBase;
typedef enum eGPUDataSource {
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
index 00d10776864..18ea6d18caf 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
@@ -24,6 +24,8 @@
#include "BLI_sys_types.h"
+struct GPUUniformBuf;
+
namespace blender {
namespace gpu {
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index 188c8786665..a83654d31e7 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -616,8 +616,8 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
GPU_framebuffer_ensure_config(&dfbl->stereo_comp_fb,
{
GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(dtxl->color),
GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color),
});
GPUVertFormat *vert_format = immVertexFormat();
@@ -628,8 +628,8 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
GPU_matrix_identity_set();
GPU_matrix_identity_projection_set();
immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE);
- immUniform1i("imageTexture", 0);
- immUniform1i("overlayTexture", 1);
+ immUniform1i("overlayTexture", 0);
+ immUniform1i("imageTexture", 1);
int settings = stereo_format->display_mode;
if (settings == S3D_DISPLAY_ANAGLYPH) {
switch (stereo_format->anaglyph_type) {
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 957352595ed..58ddc918f61 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -382,6 +382,8 @@ bool IMB_anim_can_produce_frames(const struct anim *anim);
int ismovie(const char *filepath);
void IMB_anim_set_preseek(struct anim *anim, int preseek);
int IMB_anim_get_preseek(struct anim *anim);
+int IMB_anim_get_image_width(struct anim *anim);
+int IMB_anim_get_image_height(struct anim *anim);
/**
*
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index d825b20f5f2..9b01ea0840f 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -1506,3 +1506,13 @@ int IMB_anim_get_preseek(struct anim *anim)
{
return anim->preseek;
}
+
+int IMB_anim_get_image_width(struct anim *anim)
+{
+ return anim->x;
+}
+
+int IMB_anim_get_image_height(struct anim *anim)
+{
+ return anim->y;
+}
diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
index a0d9257b822..2098b8b2505 100644
--- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
+++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
@@ -29,7 +29,6 @@
#include <Alembic/Abc/OObject.h>
struct Depsgraph;
-struct ID;
struct Object;
namespace blender::io::alembic {
diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.h b/source/blender/io/alembic/exporter/abc_writer_abstract.h
index d23e69cf73e..4997e498199 100644
--- a/source/blender/io/alembic/exporter/abc_writer_abstract.h
+++ b/source/blender/io/alembic/exporter/abc_writer_abstract.h
@@ -29,7 +29,6 @@
#include "DNA_material_types.h"
struct IDProperty;
-struct Material;
struct Object;
namespace blender::io::alembic {
diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.h b/source/blender/io/alembic/exporter/abc_writer_hair.h
index 3759ffa4310..901fd70601f 100644
--- a/source/blender/io/alembic/exporter/abc_writer_hair.h
+++ b/source/blender/io/alembic/exporter/abc_writer_hair.h
@@ -23,9 +23,6 @@
#include <Alembic/AbcGeom/OCurves.h>
#include <vector>
-struct ParticleSettings;
-struct ParticleSystem;
-
namespace blender::io::alembic {
class ABCHairWriter : public ABCAbstractWriter {
diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h
index 2a4fd6bd8fb..67000194aa1 100644
--- a/source/blender/io/alembic/intern/abc_reader_archive.h
+++ b/source/blender/io/alembic/intern/abc_reader_archive.h
@@ -28,7 +28,6 @@
#include <fstream>
struct Main;
-struct Scene;
namespace blender::io::alembic {
diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
index e066ca8ba8f..300c555ac8f 100644
--- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h
+++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
@@ -43,13 +43,11 @@
#include <set>
#include <string>
-struct Base;
struct Depsgraph;
struct DupliObject;
struct ID;
struct Object;
struct ParticleSystem;
-struct ViewLayer;
namespace blender::io {
diff --git a/source/blender/io/usd/intern/usd_exporter_context.h b/source/blender/io/usd/intern/usd_exporter_context.h
index 41ff34b327e..66e87f0eed1 100644
--- a/source/blender/io/usd/intern/usd_exporter_context.h
+++ b/source/blender/io/usd/intern/usd_exporter_context.h
@@ -24,7 +24,6 @@
#include <pxr/usd/usd/common.h>
struct Depsgraph;
-struct Object;
namespace blender::io::usd {
diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.h b/source/blender/io/usd/intern/usd_hierarchy_iterator.h
index 922ab761bd9..cd19becbb07 100644
--- a/source/blender/io/usd/intern/usd_hierarchy_iterator.h
+++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.h
@@ -28,7 +28,6 @@
#include <pxr/usd/usd/timeCode.h>
struct Depsgraph;
-struct ID;
struct Object;
namespace blender::io::usd {
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h
index 6a3b8d515dc..2143164e3dd 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.h
+++ b/source/blender/io/usd/intern/usd_writer_abstract.h
@@ -33,7 +33,6 @@
#include "DNA_material_types.h"
struct Material;
-struct Object;
namespace blender::io::usd {
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index b9ea90736ff..40e2d0d8674 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -25,7 +25,6 @@
extern "C" {
#endif
-struct Scene;
struct bContext;
struct USDExportParams {
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index af8e83a2c44..265baa16cc5 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -509,6 +509,8 @@ typedef enum ID_Type {
#define ID_IS_OVERRIDE_LIBRARY_TEMPLATE(_id) \
(((ID *)(_id))->override_library != NULL && ((ID *)(_id))->override_library->reference == NULL)
+#define ID_IS_ASSET(_id) (((const ID *)(_id))->asset_data != NULL)
+
/* Check whether datablock type is covered by copy-on-write. */
#define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_PAL, ID_IM))
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 96e870cff8e..f12934c9104 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -457,6 +457,7 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_SMEAR = 29,
SCULPT_TOOL_BOUNDARY = 30,
SCULPT_TOOL_DISPLACEMENT_ERASER = 31,
+ SCULPT_TOOL_DISPLACEMENT_SMEAR = 32,
} eBrushSculptTool;
/* Brush.uv_sculpt_tool */
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 4b020019062..1709ea5dc63 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -373,7 +373,7 @@ typedef struct Brush {
typedef struct tPaletteColorHSV {
float rgb[3];
float value;
- float h;
+ float h;
float s;
float v;
} tPaletteColorHSV;
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index ae0bb20e529..832d55ea151 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -75,8 +75,7 @@ typedef struct CustomData {
* MUST be >= CD_NUMTYPES, but we cant use a define here.
* Correct size is ensured in CustomData_update_typemap assert().
*/
- int typemap[50];
- char _pad[4];
+ int typemap[51];
/** Number of layers, size of layers array. */
int totlayer, maxlayer;
/** In editmode, total size of all data layers. */
@@ -156,7 +155,9 @@ typedef enum CustomDataType {
CD_PROP_FLOAT3 = 48,
CD_PROP_FLOAT2 = 49,
- CD_NUMTYPES = 50,
+ CD_PROP_BOOL = 50,
+
+ CD_NUMTYPES = 51,
} CustomDataType;
/* Bits for CustomDataMask */
@@ -208,6 +209,7 @@ typedef enum CustomDataType {
#define CD_MASK_PROP_COLOR (1ULL << CD_PROP_COLOR)
#define CD_MASK_PROP_FLOAT3 (1ULL << CD_PROP_FLOAT3)
#define CD_MASK_PROP_FLOAT2 (1ULL << CD_PROP_FLOAT2)
+#define CD_MASK_PROP_BOOL (1ULL << CD_PROP_BOOL)
/** Multires loop data. */
#define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK)
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index bd5afc457ac..9ac40495887 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -351,6 +351,7 @@ typedef enum eArrayGpencil_Flag {
GP_ARRAY_USE_OFFSET = (1 << 7),
GP_ARRAY_USE_RELATIVE = (1 << 8),
GP_ARRAY_USE_OB_OFFSET = (1 << 9),
+ GP_ARRAY_UNIFORM_RANDOM_SCALE = (1 << 10),
} eArrayGpencil_Flag;
typedef struct BuildGpencilModifierData {
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 212f0bfa1c9..949b0bb5bf5 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -32,8 +32,8 @@ extern "C" {
#endif
struct AnimData;
-struct MDeformVert;
struct Curve;
+struct MDeformVert;
#define GP_DEFAULT_PIX_FACTOR 1.0f
#define GP_DEFAULT_GRID_LINES 4
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 04fbc030ed9..c2337b28e54 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -35,7 +35,6 @@ struct AnimData;
struct BVHCache;
struct Ipo;
struct Key;
-struct LinkNode;
struct MCol;
struct MEdge;
struct MFace;
@@ -44,7 +43,6 @@ struct MLoopCol;
struct MLoopTri;
struct MLoopUV;
struct MPoly;
-struct MPropCol;
struct MVert;
struct Material;
struct Mesh;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index d512d8ffe34..7ad339c66af 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -33,6 +33,7 @@ extern "C" {
#endif
struct AnimData;
+struct Collection;
struct ID;
struct Image;
struct ListBase;
@@ -43,7 +44,6 @@ struct bNodePreview;
struct bNodeTreeExec;
struct bNodeType;
struct uiBlock;
-struct Collection;
#define NODE_MAXSTR 64
@@ -1084,6 +1084,10 @@ typedef struct NodeAttributeMix {
uint8_t input_type_b;
} NodeAttributeMix;
+typedef struct NodeAttributeColorRamp {
+ ColorBand color_ramp;
+} NodeAttributeColorRamp;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1501,6 +1505,11 @@ typedef enum GeometryNodeAttributeInputMode {
GEO_NODE_ATTRIBUTE_INPUT_COLOR = 3,
} GeometryNodeAttributeInputMode;
+typedef enum GeometryNodePointDistributeMethod {
+ GEO_NODE_POINT_DISTRIBUTE_RANDOM = 0,
+ GEO_NODE_POINT_DISTRIBUTE_POISSON = 1,
+} GeometryNodePointDistributeMethod;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 0a3a2cd0b64..8b13db8a012 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -38,9 +38,8 @@ extern "C" {
struct AnimData;
struct BoundBox;
-struct DerivedMesh;
struct FluidsimSettings;
-struct GpencilBatchCache;
+struct GeometrySet;
struct Ipo;
struct Material;
struct Mesh;
@@ -51,7 +50,6 @@ struct RigidBodyOb;
struct SculptSession;
struct SoftBody;
struct bGPdata;
-struct GeometrySet;
/* Vertex Groups - Name Info */
typedef struct bDeformGroup {
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 8d43483dfe4..f73f99eb4e7 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1339,6 +1339,18 @@ typedef struct MeshStatVis {
float sharp_min, sharp_max;
} MeshStatVis;
+typedef struct SequencerToolSettings {
+ /* eSeqImageFitMethod */
+ int fit_method;
+} SequencerToolSettings;
+
+typedef enum eSeqImageFitMethod {
+ SEQ_SCALE_TO_FIT,
+ SEQ_SCALE_TO_FILL,
+ SEQ_STRETCH_TO_FILL,
+ SEQ_USE_ORIGINAL_SIZE,
+} eSeqImageFitMethod;
+
/* *************************************************************** */
/* Tool Settings */
@@ -1513,6 +1525,9 @@ typedef struct ToolSettings {
* Temporary until there is a proper preset system that stores the profiles or maybe stores
* entire bevel configurations. */
struct CurveProfile *custom_bevel_profile_preset;
+
+ struct SequencerToolSettings *sequencer_tool_settings;
+
} ToolSettings;
/* *************************************************************** */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 4161faca386..4276e8b568e 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -621,6 +621,10 @@ typedef enum eSpaceSeq_Flag {
SEQ_SHOW_METADATA = (1 << 10),
SEQ_SHOW_MARKERS = (1 << 11), /* show markers region */
SEQ_ZOOM_TO_FIT = (1 << 12),
+ SEQ_SHOW_STRIP_OVERLAY = (1 << 13),
+ SEQ_SHOW_STRIP_NAME = (1 << 14),
+ SEQ_SHOW_STRIP_SOURCE = (1 << 15),
+ SEQ_SHOW_STRIP_DURATION = (1 << 16),
} eSpaceSeq_Flag;
/* SpaceSeq.view */
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index 95f6340174a..f98ca47d767 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -44,6 +44,7 @@ const EnumPropertyItem rna_enum_attribute_type_items[] = {
{CD_PROP_COLOR, "FLOAT_COLOR", 0, "Float Color", "RGBA color with floating-point precisions"},
{CD_MLOOPCOL, "BYTE_COLOR", 0, "Byte Color", "RGBA color with 8-bit precision"},
{CD_PROP_STRING, "STRING", 0, "String", "Text string"},
+ {CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 08c655d493c..a361feba439 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -134,6 +134,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""},
{SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
{SCULPT_TOOL_DISPLACEMENT_ERASER, "DISPLACEMENT_ERASER", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Eraser", ""},
+ {SCULPT_TOOL_DISPLACEMENT_SMEAR, "DISPLACEMENT_SMEAR", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Smear", ""},
{SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""},
{SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""},
{SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""},
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 5f131de6a40..89eb989a442 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -1560,6 +1560,12 @@ static void rna_def_modifier_gpencilarray(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_USE_RELATIVE);
RNA_def_property_ui_text(prop, "Shift", "Enable shift");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_uniform_random_scale", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_UNIFORM_RANDOM_SCALE);
+ RNA_def_property_ui_text(
+ prop, "Uniform Scale", "Use the same random seed for each scale axis for a uniform scale");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
static void rna_def_modifier_gpencilbuild(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 153e2aebd22..d4ac3d1b084 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -452,6 +452,20 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem rna_node_geometry_point_distribute_method_items[] = {
+ {GEO_NODE_POINT_DISTRIBUTE_RANDOM,
+ "RANDOM",
+ 0,
+ "Random",
+ "Distribute points randomly on the surface"},
+ {GEO_NODE_POINT_DISTRIBUTE_POISSON,
+ "POISSON",
+ 0,
+ "Poisson Disk",
+ "Project points on the surface evenly with a Poisson disk distribution"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#endif
#ifdef RNA_RUNTIME
@@ -1876,7 +1890,7 @@ static const EnumPropertyItem *itemf_function_check(
static bool attribute_random_type_supported(const EnumPropertyItem *item)
{
- return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3);
+ return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL);
}
static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_type_itemf(
bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
@@ -1898,7 +1912,7 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_domain_itemf(
static bool attribute_fill_type_supported(const EnumPropertyItem *item)
{
- return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR);
+ return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL);
}
static const EnumPropertyItem *rna_GeometryNodeAttributeFill_type_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
@@ -8388,7 +8402,7 @@ static void def_geo_attribute_create_common(StructRNA *srna,
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_geo_random_attribute(StructRNA *srna)
+static void def_geo_attribute_randomize(StructRNA *srna)
{
def_geo_attribute_create_common(srna,
"rna_GeometryNodeAttributeRandom_type_itemf",
@@ -8481,6 +8495,30 @@ static void def_geo_attribute_mix(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_point_distribute(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "distribute_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_node_geometry_point_distribute_method_items);
+ RNA_def_property_enum_default(prop, GEO_NODE_POINT_DISTRIBUTE_RANDOM);
+ RNA_def_property_ui_text(prop, "Distribution Method", "Method to use for scattering points");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
+static void def_geo_attribute_color_ramp(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeAttributeColorRamp", "storage");
+
+ prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ColorRamp");
+ RNA_def_property_ui_text(prop, "Color Ramp", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index e149bb4ecad..7cae88d292b 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2200,6 +2200,11 @@ static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("tool_settings.curve_paint_settings");
}
+static char *rna_SequencerToolSettings_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.sequencer_tool_settings");
+}
+
/* generic function to recalc geometry */
static void rna_EditMesh_update(bContext *C, PointerRNA *UNUSED(ptr))
{
@@ -3584,6 +3589,38 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "custom_bevel_profile_preset");
RNA_def_property_struct_type(prop, "CurveProfile");
RNA_def_property_ui_text(prop, "Curve Profile Widget", "Used for defining a profile's path");
+
+ /* Sequencer tool settings */
+ prop = RNA_def_property(srna, "sequencer_tool_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "SequencerToolSettings");
+ RNA_def_property_ui_text(prop, "Sequencer Tool Settings", NULL);
+}
+
+static void rna_def_sequencer_tool_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem scale_fit_methods[] = {
+ {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"},
+ {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"},
+ {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image to fill the canvas"},
+ {SEQ_USE_ORIGINAL_SIZE,
+ "ORIGINAL",
+ 0,
+ "Use Original Size",
+ "Keep image at its original size"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "SequencerToolSettings", NULL);
+ RNA_def_struct_path_func(srna, "rna_SequencerToolSettings_path");
+ RNA_def_struct_ui_text(srna, "Sequencer Tool Settings", "");
+
+ prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, scale_fit_methods);
+ RNA_def_property_ui_text(prop, "Fit Method", "Scale fit method");
}
static void rna_def_unified_paint_settings(BlenderRNA *brna)
@@ -7968,6 +8005,7 @@ void RNA_def_scene(BlenderRNA *brna)
rna_def_gpencil_interpolate(brna);
rna_def_unified_paint_settings(brna);
rna_def_curve_paint_settings(brna);
+ rna_def_sequencer_tool_settings(brna);
rna_def_statvis(brna);
rna_def_unit_settings(brna);
rna_def_scene_image_format_data(brna);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 0e779c8cc97..2f821dad811 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -2602,7 +2602,7 @@ static int rna_FileBrowser_FileSelectEntry_name_length(PointerRNA *ptr)
static int rna_FileBrowser_FileSelectEntry_preview_icon_id_get(PointerRNA *ptr)
{
const FileDirEntry *entry = ptr->data;
- return entry->preview_icon_id;
+ return ED_file_icon(entry);
}
static PointerRNA rna_FileBrowser_FileSelectEntry_asset_data_get(PointerRNA *ptr)
@@ -5176,7 +5176,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
prop = RNA_def_property(srna, "waveform_display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, waveform_type_display_items);
- RNA_def_property_ui_text(prop, "Waveform Displaying", "How Waveforms are drawn");
+ RNA_def_property_ui_text(prop, "Waveform Display", "How Waveforms are drawn");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
prop = RNA_def_property(srna, "use_zoom_to_fit", PROP_BOOLEAN, PROP_NONE);
@@ -5229,6 +5229,27 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_FCURVES);
RNA_def_property_ui_text(prop, "Show F-Curves", "Display strip opacity/volume curve");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_strip_overlay", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_OVERLAY);
+ RNA_def_property_ui_text(prop, "Show Overlay", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_strip_name", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_NAME);
+ RNA_def_property_ui_text(prop, "Show Name", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_strip_source", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_SOURCE);
+ RNA_def_property_ui_text(
+ prop, "Show Source", "Display path to source file, or name of source datablock");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_strip_duration", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_DURATION);
+ RNA_def_property_ui_text(prop, "Show Duration", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
}
static void rna_def_space_text(BlenderRNA *brna)
diff --git a/source/blender/modifiers/MOD_nodes.h b/source/blender/modifiers/MOD_nodes.h
index 9c75e7e3416..907dbe9c5f4 100644
--- a/source/blender/modifiers/MOD_nodes.h
+++ b/source/blender/modifiers/MOD_nodes.h
@@ -17,8 +17,8 @@
#pragma once
struct Main;
-struct Object;
struct NodesModifierData;
+struct Object;
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 11852f6f723..bc0e7972bcb 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -138,8 +138,10 @@ set(SRC
function/nodes/node_fn_switch.cc
function/node_function_util.cc
+ geometry/nodes/node_geo_attribute_color_ramp.cc
geometry/nodes/node_geo_attribute_fill.cc
geometry/nodes/node_geo_attribute_math.cc
+ geometry/nodes/node_geo_attribute_randomize.cc
geometry/nodes/node_geo_boolean.cc
geometry/nodes/node_geo_common.cc
geometry/nodes/node_geo_edge_split.cc
@@ -147,8 +149,8 @@ set(SRC
geometry/nodes/node_geo_attribute_mix.cc
geometry/nodes/node_geo_object_info.cc
geometry/nodes/node_geo_point_distribute.cc
+ geometry/nodes/node_geo_point_distribute_poisson_disk.cc
geometry/nodes/node_geo_point_instance.cc
- geometry/nodes/node_geo_random_attribute.cc
geometry/nodes/node_geo_subdivision_surface.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index e3ec0451832..f1cd55ce048 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -35,10 +35,11 @@ void register_node_type_geo_triangulate(void);
void register_node_type_geo_point_distribute(void);
void register_node_type_geo_point_instance(void);
void register_node_type_geo_object_info(void);
-void register_node_type_geo_random_attribute(void);
+void register_node_type_geo_attribute_randomize(void);
void register_node_type_geo_attribute_math(void);
void register_node_type_geo_join_geometry(void);
void register_node_type_geo_attribute_mix(void);
+void register_node_type_geo_attribute_color_ramp(void);
#ifdef __cplusplus
}
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 5fe554e0478..445e1ed6af2 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -26,6 +26,8 @@
namespace blender::nodes {
+using bke::BooleanReadAttribute;
+using bke::BooleanWriteAttribute;
using bke::Color4fReadAttribute;
using bke::Color4fWriteAttribute;
using bke::Float3ReadAttribute;
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 491f49cf425..662952abb59 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -271,14 +271,15 @@ DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Spl
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "")
-DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, 0, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "")
+DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, def_geo_point_distribute, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "")
DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, def_geo_point_instance, "POINT_INSTANCE", PointInstance, "Point Instance", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "")
-DefNode(GeometryNode, GEO_NODE_RANDOM_ATTRIBUTE, def_geo_random_attribute, "RANDOM_ATTRIBUTE", RandomAttribute, "Random Attribute", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "ATTRIBUTE_RANDOMIZE", AttributeRandomize, "Attribute Randomize", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MATH, def_geo_attribute_math, "ATTRIBUTE_MATH", AttributeMath, "Attribute Math", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_FILL, def_geo_attribute_fill, "ATTRIBUTE_FILL", AttributeFill, "Attribute Fill", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_MIX", AttributeMix, "Attribute Mix", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "ATTRIBUTE_COLOR_RAMP", AttributeColorRamp, "Attribute Color Ramp", "")
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index ec389961615..c97463cdc22 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -42,4 +42,10 @@ namespace blender::nodes {
void update_attribute_input_socket_availabilities(bNode &node,
const StringRef name,
const GeometryNodeAttributeInputMode mode);
-}
+
+void poisson_disk_point_elimination(Vector<float3> const *input_points,
+ Vector<float3> *output_points,
+ float maximum_distance,
+ float3 boundbox);
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
new file mode 100644
index 00000000000..3f7023ba88f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
@@ -0,0 +1,107 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+#include "BKE_colorband.h"
+
+static bNodeSocketTemplate geo_node_attribute_color_ramp_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_STRING, N_("Attribute")},
+ {SOCK_STRING, N_("Result")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_attribute_color_ramp_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static void execute_on_component(const GeoNodeExecParams &params, GeometryComponent &component)
+{
+ const bNode &bnode = params.node();
+ NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)bnode.storage;
+
+ const std::string result_name = params.get_input<std::string>("Result");
+ /* Once we support more domains at the user level, we have to decide how the result domain is
+ * choosen. */
+ const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
+ const CustomDataType result_type = CD_PROP_COLOR;
+
+ WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write(
+ result_name, result_domain, result_type);
+ if (!attribute_result) {
+ return;
+ }
+
+ Color4fWriteAttribute attribute_out = std::move(attribute_result);
+
+ const std::string input_name = params.get_input<std::string>("Attribute");
+ FloatReadAttribute attribute_in = component.attribute_get_for_read<float>(
+ input_name, result_domain, 0.0f);
+
+ Span<float> data_in = attribute_in.get_span();
+ MutableSpan<Color4f> data_out = attribute_out.get_span();
+
+ ColorBand *color_ramp = &node_storage->color_ramp;
+ for (const int i : data_in.index_range()) {
+ BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]);
+ }
+
+ attribute_out.apply_span();
+}
+
+static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ if (geometry_set.has<MeshComponent>()) {
+ execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
+ }
+ if (geometry_set.has<PointCloudComponent>()) {
+ execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
+ }
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN(
+ sizeof(NodeAttributeColorRamp), __func__);
+ BKE_colorband_init(&node_storage->color_ramp, true);
+ node->storage = node_storage;
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_attribute_color_ramp()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_ATTRIBUTE_COLOR_RAMP, "Attribute Color Ramp", NODE_CLASS_ATTRIBUTE, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_attribute_color_ramp_in, geo_node_attribute_color_ramp_out);
+ node_type_storage(
+ &ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage);
+ node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
index d3c7e86b708..5cdbd18ecc8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
@@ -27,6 +27,7 @@ static bNodeSocketTemplate geo_node_attribute_fill_in[] = {
{SOCK_VECTOR, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{SOCK_FLOAT, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{SOCK_RGBA, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
+ {SOCK_BOOLEAN, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{-1, ""},
};
@@ -45,12 +46,14 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node
bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *socket_value_float = socket_value_vector->next;
bNodeSocket *socket_value_color4f = socket_value_float->next;
+ bNodeSocket *socket_value_boolean = socket_value_color4f->next;
const CustomDataType data_type = static_cast<CustomDataType>(node->custom1);
nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3);
nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT);
nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL);
}
namespace blender::nodes {
@@ -96,6 +99,14 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
color4f_attribute.apply_span();
break;
}
+ case CD_PROP_BOOL: {
+ BooleanWriteAttribute boolean_attribute = std::move(attribute);
+ const bool value = params.get_input<bool>("Value_003");
+ MutableSpan<bool> attribute_span = boolean_attribute.get_span();
+ attribute_span.fill(value);
+ boolean_attribute.apply_span();
+ break;
+ }
default:
break;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index 5cacb96412c..53df2e8c087 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -21,7 +21,7 @@
#include "DNA_mesh_types.h"
#include "DNA_pointcloud_types.h"
-static bNodeSocketTemplate geo_node_random_attribute_in[] = {
+static bNodeSocketTemplate geo_node_attribute_randomize_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Attribute")},
{SOCK_VECTOR, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
@@ -32,17 +32,17 @@ static bNodeSocketTemplate geo_node_random_attribute_in[] = {
{-1, ""},
};
-static bNodeSocketTemplate geo_node_random_attribute_out[] = {
+static bNodeSocketTemplate geo_node_attribute_randomize_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
-static void geo_node_random_attribute_init(bNodeTree *UNUSED(tree), bNode *node)
+static void geo_node_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = CD_PROP_FLOAT;
}
-static void geo_node_random_attribute_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void geo_node_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -59,6 +59,16 @@ static void geo_node_random_attribute_update(bNodeTree *UNUSED(ntree), bNode *no
namespace blender::nodes {
+static void randomize_attribute(BooleanWriteAttribute &attribute, RandomNumberGenerator &rng)
+{
+ MutableSpan<bool> attribute_span = attribute.get_span();
+ for (const int i : IndexRange(attribute.size())) {
+ const bool value = rng.get_float() > 0.5f;
+ attribute_span[i] = value;
+ }
+ attribute.apply_span();
+}
+
static void randomize_attribute(FloatWriteAttribute &attribute,
float min,
float max,
@@ -121,6 +131,11 @@ static void randomize_attribute(GeometryComponent &component,
randomize_attribute(float3_attribute, min_value, max_value, rng);
break;
}
+ case CD_PROP_BOOL: {
+ BooleanWriteAttribute boolean_attribute = std::move(attribute);
+ randomize_attribute(boolean_attribute, rng);
+ break;
+ }
default:
break;
}
@@ -147,15 +162,16 @@ static void geo_node_random_attribute_exec(GeoNodeExecParams params)
} // namespace blender::nodes
-void register_node_type_geo_random_attribute()
+void register_node_type_geo_attribute_randomize()
{
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_RANDOM_ATTRIBUTE, "Random Attribute", NODE_CLASS_ATTRIBUTE, 0);
- node_type_socket_templates(&ntype, geo_node_random_attribute_in, geo_node_random_attribute_out);
- node_type_init(&ntype, geo_node_random_attribute_init);
- node_type_update(&ntype, geo_node_random_attribute_update);
+ &ntype, GEO_NODE_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_attribute_randomize_in, geo_node_attribute_randomize_out);
+ node_type_init(&ntype, geo_node_attribute_randomize_init);
+ node_type_update(&ntype, geo_node_attribute_randomize_update);
ntype.geometry_node_execute = blender::nodes::geo_node_random_attribute_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
index 2f5f7e264bc..8be9636e14d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -24,6 +24,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
+#include "BKE_bvhutils.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
@@ -33,8 +34,10 @@
static bNodeSocketTemplate geo_node_point_distribute_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
- {SOCK_FLOAT, N_("Density"), 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
+ {SOCK_FLOAT, N_("Minimum Distance"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
+ {SOCK_FLOAT, N_("Maximum Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
{SOCK_STRING, N_("Density Attribute")},
+ {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000},
{-1, ""},
};
@@ -43,11 +46,19 @@ static bNodeSocketTemplate geo_node_point_distribute_out[] = {
{-1, ""},
};
+static void node_point_distribute_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+
+ nodeSetSocketAvailability(sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON));
+}
+
namespace blender::nodes {
-static Vector<float3> scatter_points_from_mesh(const Mesh *mesh,
- const float density,
- const FloatReadAttribute &density_factors)
+static Vector<float3> random_scatter_points_from_mesh(const Mesh *mesh,
+ const float density,
+ const FloatReadAttribute &density_factors,
+ const int seed)
{
/* This only updates a cache and can be considered to be logically const. */
const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(mesh));
@@ -71,7 +82,7 @@ static Vector<float3> scatter_points_from_mesh(const Mesh *mesh,
3.0f;
const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
- const int looptri_seed = BLI_hash_int(looptri_index);
+ const int looptri_seed = BLI_hash_int(looptri_index + seed);
RandomNumberGenerator looptri_rng(looptri_seed);
const float points_amount_fl = area * density * looptri_density_factor;
@@ -90,17 +101,158 @@ static Vector<float3> scatter_points_from_mesh(const Mesh *mesh,
return points;
}
+struct RayCastAll_Data {
+ void *bvhdata;
+
+ BVHTree_RayCastCallback raycast_callback;
+
+ const Mesh *mesh;
+ float base_weight;
+ FloatReadAttribute *density_factors;
+ Vector<float3> *projected_points;
+ float cur_point_weight;
+};
+
+static void project_2d_bvh_callback(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
+{
+ struct RayCastAll_Data *data = (RayCastAll_Data *)userdata;
+ data->raycast_callback(data->bvhdata, index, ray, hit);
+ if (hit->index != -1) {
+ /* This only updates a cache and can be considered to be logically const. */
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(data->mesh));
+ const MVert *mvert = data->mesh->mvert;
+
+ const MLoopTri &looptri = looptris[index];
+ const FloatReadAttribute &density_factors = data->density_factors[0];
+
+ const int v0_index = data->mesh->mloop[looptri.tri[0]].v;
+ const int v1_index = data->mesh->mloop[looptri.tri[1]].v;
+ const int v2_index = data->mesh->mloop[looptri.tri[2]].v;
+
+ const float v0_density_factor = std::max(0.0f, density_factors[v0_index]);
+ const float v1_density_factor = std::max(0.0f, density_factors[v1_index]);
+ const float v2_density_factor = std::max(0.0f, density_factors[v2_index]);
+
+ /* Calculate barycentric weights for hit point. */
+ float3 weights;
+ interp_weights_tri_v3(
+ weights, mvert[v0_index].co, mvert[v1_index].co, mvert[v2_index].co, hit->co);
+
+ float point_weight = weights[0] * v0_density_factor + weights[1] * v1_density_factor +
+ weights[2] * v2_density_factor;
+
+ point_weight *= data->base_weight;
+
+ if (point_weight >= FLT_EPSILON && data->cur_point_weight <= point_weight) {
+ data->projected_points->append(hit->co);
+ }
+ }
+}
+
+static Vector<float3> poisson_scatter_points_from_mesh(const Mesh *mesh,
+ const float density,
+ const float minimum_distance,
+ const FloatReadAttribute &density_factors,
+ const int seed)
+{
+ Vector<float3> points;
+
+ if (minimum_distance <= FLT_EPSILON || density <= FLT_EPSILON) {
+ return points;
+ }
+
+ /* Scatter points randomly on the mesh with higher density (5-7) times higher than desired for
+ * good quality possion disk distributions. */
+ int quality = 5;
+ const int output_points_target = 1000;
+ points.resize(output_points_target * quality);
+
+ const float required_area = output_points_target *
+ (2.0f * sqrtf(3.0f) * minimum_distance * minimum_distance);
+ const float point_scale_multiplier = sqrtf(required_area);
+
+ {
+ const int rnd_seed = BLI_hash_int(seed);
+ RandomNumberGenerator point_rng(rnd_seed);
+
+ for (int i = 0; i < points.size(); i++) {
+ points[i].x = point_rng.get_float() * point_scale_multiplier;
+ points[i].y = point_rng.get_float() * point_scale_multiplier;
+ points[i].z = 0.0f;
+ }
+ }
+
+ /* Eliminate the scattered points until we get a possion distribution. */
+ Vector<float3> output_points(output_points_target);
+
+ const float3 bounds_max = float3(point_scale_multiplier, point_scale_multiplier, 0);
+ poisson_disk_point_elimination(&points, &output_points, 2.0f * minimum_distance, bounds_max);
+ Vector<float3> final_points;
+ final_points.reserve(output_points_target);
+
+ /* Check if we have any points we should remove from the final possion distribition. */
+ BVHTreeFromMesh treedata;
+ BKE_bvhtree_from_mesh_get(&treedata, const_cast<Mesh *>(mesh), BVHTREE_FROM_LOOPTRI, 2);
+
+ float3 bb_min, bb_max;
+ BLI_bvhtree_get_bounding_box(treedata.tree, bb_min, bb_max);
+
+ struct RayCastAll_Data data;
+ data.bvhdata = &treedata;
+ data.raycast_callback = treedata.raycast_callback;
+ data.mesh = mesh;
+ data.projected_points = &final_points;
+ data.density_factors = const_cast<FloatReadAttribute *>(&density_factors);
+ data.base_weight = std::min(
+ 1.0f, density / (output_points.size() / (point_scale_multiplier * point_scale_multiplier)));
+
+ const float max_dist = bb_max[2] - bb_min[2] + 2.0f;
+ const float3 dir = float3(0, 0, -1);
+ float3 raystart;
+ raystart.z = bb_max[2] + 1.0f;
+
+ float tile_start_x_coord = bb_min[0];
+ int tile_repeat_x = ceilf((bb_max[0] - bb_min[0]) / point_scale_multiplier);
+
+ float tile_start_y_coord = bb_min[1];
+ int tile_repeat_y = ceilf((bb_max[1] - bb_min[1]) / point_scale_multiplier);
+
+ for (int x = 0; x < tile_repeat_x; x++) {
+ float tile_curr_x_coord = x * point_scale_multiplier + tile_start_x_coord;
+ for (int y = 0; y < tile_repeat_y; y++) {
+ float tile_curr_y_coord = y * point_scale_multiplier + tile_start_y_coord;
+ for (int idx = 0; idx < output_points.size(); idx++) {
+ raystart.x = output_points[idx].x + tile_curr_x_coord;
+ raystart.y = output_points[idx].y + tile_curr_y_coord;
+
+ data.cur_point_weight = (float)idx / (float)output_points.size();
+
+ BLI_bvhtree_ray_cast_all(
+ treedata.tree, raystart, dir, 0.0f, max_dist, project_2d_bvh_callback, &data);
+ }
+ }
+ }
+
+ return final_points;
+}
+
static void geo_node_point_distribute_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
+ GeometryNodePointDistributeMethod distribute_method =
+ static_cast<GeometryNodePointDistributeMethod>(params.node().custom1);
+
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", std::move(geometry_set_out));
return;
}
- const float density = params.extract_input<float>("Density");
+ const float density = params.extract_input<float>("Maximum Density");
const std::string density_attribute = params.extract_input<std::string>("Density Attribute");
if (density <= 0.0f) {
@@ -113,8 +265,19 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read<float>(
density_attribute, ATTR_DOMAIN_POINT, 1.0f);
+ const int seed = params.get_input<int>("Seed");
- Vector<float3> points = scatter_points_from_mesh(mesh_in, density, density_factors);
+ Vector<float3> points;
+
+ switch (distribute_method) {
+ case GEO_NODE_POINT_DISTRIBUTE_RANDOM:
+ points = random_scatter_points_from_mesh(mesh_in, density, density_factors, seed);
+ break;
+ case GEO_NODE_POINT_DISTRIBUTE_POISSON:
+ const float min_dist = params.extract_input<float>("Minimum Distance");
+ points = poisson_scatter_points_from_mesh(mesh_in, density, min_dist, density_factors, seed);
+ break;
+ }
PointCloud *pointcloud = BKE_pointcloud_new_nomain(points.size());
memcpy(pointcloud->co, points.data(), sizeof(float3) * points.size());
@@ -135,6 +298,7 @@ void register_node_type_geo_point_distribute()
geo_node_type_base(
&ntype, GEO_NODE_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(&ntype, geo_node_point_distribute_in, geo_node_point_distribute_out);
+ node_type_update(&ntype, node_point_distribute_update);
ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc
new file mode 100644
index 00000000000..47764efa15d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc
@@ -0,0 +1,281 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Based on Cem Yuksel. 2015. Sample Elimination for Generating Poisson Disk Sample
+ * ! Sets. Computer Graphics Forum 34, 2 (May 2015), 25-32.
+ * ! http://www.cemyuksel.com/research/sampleelimination/
+ * Copyright (c) 2016, Cem Yuksel <cem@cemyuksel.com>
+ * All rights reserved.
+ */
+
+#include "BLI_inplace_priority_queue.hh"
+#include "BLI_kdtree.h"
+
+#include "node_geometry_util.hh"
+
+#include <iostream>
+#include <string.h>
+
+namespace blender::nodes {
+
+static void tile_point(Vector<float3> *tiled_points,
+ Vector<size_t> *indices,
+ const float maximum_distance,
+ const float3 boundbox,
+ float3 const &point,
+ size_t index,
+ int dimension = 0)
+{
+ for (int dimension_iter = dimension; dimension_iter < 3; dimension_iter++) {
+ if (boundbox[dimension_iter] - point[dimension_iter] < maximum_distance) {
+ float3 point_tiled = point;
+ point_tiled[dimension_iter] -= boundbox[dimension_iter];
+
+ tiled_points->append(point_tiled);
+ indices->append(index);
+
+ tile_point(tiled_points,
+ indices,
+ maximum_distance,
+ boundbox,
+ point_tiled,
+ index,
+ dimension_iter + 1);
+ }
+
+ if (point[dimension_iter] < maximum_distance) {
+ float3 point_tiled = point;
+ point_tiled[dimension_iter] += boundbox[dimension_iter];
+
+ tiled_points->append(point_tiled);
+ indices->append(index);
+
+ tile_point(tiled_points,
+ indices,
+ maximum_distance,
+ boundbox,
+ point_tiled,
+ index,
+ dimension_iter + 1);
+ }
+ }
+}
+
+/**
+ * Returns the weight the point gets based on the distance to another point.
+ */
+static float point_weight_influence_get(const float maximum_distance,
+ const float minimum_distance,
+ float distance)
+{
+ const float alpha = 8.0f;
+
+ if (distance < minimum_distance) {
+ distance = minimum_distance;
+ }
+
+ return std::pow(1.0f - distance / maximum_distance, alpha);
+}
+
+/**
+ * Weight each point based on their proximity to its neighbors
+ *
+ * For each index in the weight array add a weight based on the proximity the
+ * corresponding point has with its neighboors.
+ **/
+static void points_distance_weight_calculate(Vector<float> *weights,
+ const size_t point_id,
+ const float3 *input_points,
+ const void *kd_tree,
+ const float minimum_distance,
+ const float maximum_distance,
+ InplacePriorityQueue<float> *heap)
+{
+ KDTreeNearest_3d *nearest_point = nullptr;
+ int neighbors = BLI_kdtree_3d_range_search(
+ (KDTree_3d *)kd_tree, input_points[point_id], &nearest_point, maximum_distance);
+
+ for (int i = 0; i < neighbors; i++) {
+ size_t neighbor_point_id = nearest_point[i].index;
+
+ if (neighbor_point_id >= weights->size()) {
+ continue;
+ }
+
+ /* The point should not influence itself. */
+ if (neighbor_point_id == point_id) {
+ continue;
+ }
+
+ const float weight_influence = point_weight_influence_get(
+ maximum_distance, minimum_distance, nearest_point[i].dist);
+
+ /* In the first pass we just the weights. */
+ if (heap == nullptr) {
+ (*weights)[point_id] += weight_influence;
+ }
+ /* When we run again we need to update the weights and the heap. */
+ else {
+ (*weights)[neighbor_point_id] -= weight_influence;
+ heap->priority_decreased(neighbor_point_id);
+ }
+ }
+
+ if (nearest_point) {
+ MEM_freeN(nearest_point);
+ }
+}
+
+/**
+ * Returns the minimum radius fraction used by the default weight function.
+ */
+static float weight_limit_fraction_get(const size_t input_size, const size_t output_size)
+{
+ const float beta = 0.65f;
+ const float gamma = 1.5f;
+ float ratio = float(output_size) / float(input_size);
+ return (1.0f - std::pow(ratio, gamma)) * beta;
+}
+
+/**
+ * Tile the input points.
+ */
+static void points_tiling(const float3 *input_points,
+ const size_t input_size,
+ void **kd_tree,
+ const float maximum_distance,
+ const float3 boundbox)
+
+{
+ Vector<float3> tiled_points(input_points, input_points + input_size);
+ Vector<size_t> indices(input_size);
+
+ for (size_t i = 0; i < input_size; i++) {
+ indices[i] = i;
+ }
+
+ /* Tile the tree based on the boundbox. */
+ for (size_t i = 0; i < input_size; i++) {
+ tile_point(&tiled_points, &indices, maximum_distance, boundbox, input_points[i], i);
+ }
+
+ /* Build a new tree with the new indices and tiled points. */
+ *kd_tree = BLI_kdtree_3d_new(tiled_points.size());
+ for (size_t i = 0; i < tiled_points.size(); i++) {
+ BLI_kdtree_3d_insert(*(KDTree_3d **)kd_tree, indices[i], tiled_points[i]);
+ }
+ BLI_kdtree_3d_balance(*(KDTree_3d **)kd_tree);
+}
+
+static void weighted_sample_elimination(const float3 *input_points,
+ const size_t input_size,
+ float3 *output_points,
+ const size_t output_size,
+ const float maximum_distance,
+ const float3 boundbox,
+ const bool do_copy_eliminated)
+{
+ const float minimum_distance = maximum_distance *
+ weight_limit_fraction_get(input_size, output_size);
+
+ void *kd_tree = nullptr;
+ points_tiling(input_points, input_size, &kd_tree, maximum_distance, boundbox);
+
+ /* Assign weights to each sample. */
+ Vector<float> weights(input_size, 0.0f);
+ for (size_t point_id = 0; point_id < weights.size(); point_id++) {
+ points_distance_weight_calculate(
+ &weights, point_id, input_points, kd_tree, minimum_distance, maximum_distance, nullptr);
+ }
+
+ /* Remove the points based on their weight. */
+ InplacePriorityQueue<float> heap(weights);
+
+ size_t sample_size = input_size;
+ while (sample_size > output_size) {
+ /* For each sample around it, remove its weight contribution and update the heap. */
+ size_t point_id = heap.pop_index();
+ points_distance_weight_calculate(
+ &weights, point_id, input_points, kd_tree, minimum_distance, maximum_distance, &heap);
+ sample_size--;
+ }
+
+ /* Copy the samples to the output array. */
+ size_t target_size = do_copy_eliminated ? input_size : output_size;
+ for (size_t i = 0; i < target_size; i++) {
+ size_t index = heap.all_indices()[i];
+ output_points[i] = input_points[index];
+ }
+
+ /* Cleanup. */
+ BLI_kdtree_3d_free((KDTree_3d *)kd_tree);
+}
+
+static void progressive_sampling_reorder(Vector<float3> *output_points,
+ float maximum_density,
+ float3 boundbox)
+{
+ /* Re-order the points for progressive sampling. */
+ Vector<float3> temporary_points(output_points->size());
+ float3 *source_points = output_points->data();
+ float3 *dest_points = temporary_points.data();
+ size_t source_size = output_points->size();
+ size_t dest_size = 0;
+
+ while (source_size >= 3) {
+ dest_size = source_size * 0.5f;
+
+ /* Changes the weight function radius using half of the number of samples.
+ * It is used for progressive sampling. */
+ maximum_density *= std::sqrt(2.0f);
+ weighted_sample_elimination(
+ source_points, source_size, dest_points, dest_size, maximum_density, boundbox, true);
+
+ if (dest_points != output_points->data()) {
+ memcpy((*output_points)[dest_size],
+ dest_points[dest_size],
+ (source_size - dest_size) * sizeof(float3));
+ }
+
+ /* Swap the arrays around. */
+ float3 *points_iter = source_points;
+ source_points = dest_points;
+ dest_points = points_iter;
+ source_size = dest_size;
+ }
+ if (source_points != output_points->data()) {
+ memcpy(output_points->data(), source_points, dest_size * sizeof(float3));
+ }
+}
+
+void poisson_disk_point_elimination(Vector<float3> const *input_points,
+ Vector<float3> *output_points,
+ float maximum_density,
+ float3 boundbox)
+{
+ weighted_sample_elimination(input_points->data(),
+ input_points->size(),
+ output_points->data(),
+ output_points->size(),
+ maximum_density,
+ boundbox,
+ false);
+
+ progressive_sampling_reorder(output_points, maximum_density, boundbox);
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index 6a22adb25a7..eef2c6c9125 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -96,6 +96,9 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
if (found_socket->type == SOCK_RGBA) {
return CD_PROP_COLOR;
}
+ if (found_socket->type == SOCK_BOOLEAN) {
+ return CD_PROP_BOOL;
+ }
BLI_assert(false);
return default_type;
diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc
index ec5527a2970..2e4196af156 100644
--- a/source/blender/nodes/intern/node_tree_multi_function.cc
+++ b/source/blender/nodes/intern/node_tree_multi_function.cc
@@ -208,6 +208,10 @@ static DataTypeConversions create_implicit_conversions()
conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); });
add_implicit_conversion<Color4f, float>(
conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); });
+ add_implicit_conversion<float3, bool>(
+ conversions, "float3 to boolean", [](float3 a) { return a.length_squared() == 0.0f; });
+ add_implicit_conversion<bool, float3>(
+ conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); });
return conversions;
}
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 46b4dbc96d7..366d801a888 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -26,7 +26,6 @@ struct ID; /* DNA_ID.h */
struct ListBase; /* DNA_listBase.h */
struct Object; /* DNA_object_types.h */
struct PathResolvedRNA;
-struct ReportList;
struct Text; /* defined in DNA_text_types.h */
struct bConstraint; /* DNA_constraint_types.h */
struct bConstraintOb; /* DNA_constraint_types.h */
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 4dd2b300700..3e73ac77fc6 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -114,7 +114,7 @@ typedef struct RenderResult {
/* target image size */
int rectx, recty;
- short crop, sample_nr;
+ short sample_nr;
/* The following rect32, rectf and rectz buffers are for temporary storage only,
* for RenderResult structs created in #RE_AcquireResultImage - which do not have RenderView */
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index 769077c0e8c..5685911c42e 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -288,7 +288,7 @@ RenderResult *RE_engine_begin_result(
disprect.ymin = y;
disprect.ymax = y + h;
- result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname);
+ result = render_result_new(re, &disprect, RR_USE_MEM, layername, viewname);
/* todo: make this thread safe */
@@ -846,7 +846,7 @@ int RE_engine_render(Render *re, int do_all)
if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE)) {
savebuffers = RR_USE_EXR;
}
- re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ re->result = render_result_new(re, &re->disprect, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS);
}
BLI_rw_mutex_unlock(&re->resultmutex);
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 3d19e5e6c15..6b55b82ac97 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -905,7 +905,7 @@ static void render_result_rescale(Render *re)
if (src_rectf != NULL) {
float *dst_rectf = NULL;
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, "");
+ re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, "");
if (re->result != NULL) {
dst_rectf = RE_RenderViewGetById(re->result, 0)->rectf;
@@ -1162,7 +1162,7 @@ static void render_result_uncrop(Render *re)
/* weak is: it chances disprect from border */
render_result_disprect_to_full_resolution(re);
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ rres = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
rres->stamp_data = BKE_stamp_data_copy(re->result->stamp_data);
render_result_clone_passes(re, rres, NULL);
@@ -1358,7 +1358,7 @@ static void do_render_composite(Render *re)
if ((re->r.mode & R_CROP) == 0) {
render_result_disprect_to_full_resolution(re);
}
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
BLI_rw_mutex_unlock(&re->resultmutex);
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index dfce51ec3ab..1ed894751ce 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -285,12 +285,8 @@ RenderPass *render_layer_add_pass(RenderResult *rr,
/* will read info from Render *re to define layers */
/* called in threads */
/* re->winx,winy is coordinate space of entire image, partrct the part within */
-RenderResult *render_result_new(Render *re,
- rcti *partrct,
- int crop,
- int savebuffers,
- const char *layername,
- const char *viewname)
+RenderResult *render_result_new(
+ Render *re, rcti *partrct, int savebuffers, const char *layername, const char *viewname)
{
RenderResult *rr;
RenderLayer *rl;
@@ -308,9 +304,7 @@ RenderResult *render_result_new(Render *re,
rr->rectx = rectx;
rr->recty = recty;
rr->renrect.xmin = 0;
- rr->renrect.xmax = rectx - 2 * crop;
- /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */
- rr->crop = crop;
+ rr->renrect.xmax = rectx;
/* tilerect is relative coordinates within render disprect. do not subtract crop yet */
rr->tilerect.xmin = partrct->xmin - re->disprect.xmin;
@@ -827,20 +821,8 @@ static void do_merge_tile(
copylen = tilex = rrpart->rectx;
tiley = rrpart->recty;
- if (rrpart->crop) { /* filters add pixel extra */
- tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex);
-
- copylen = tilex - 2 * rrpart->crop;
- tiley -= 2 * rrpart->crop;
-
- ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx +
- (rrpart->tilerect.xmin + rrpart->crop);
- target += pixsize * ofs;
- }
- else {
- ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin);
- target += pixsize * ofs;
- }
+ ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin);
+ target += pixsize * ofs;
copylen *= sizeof(float) * pixsize;
tilex *= pixsize;
@@ -1107,7 +1089,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons
{
RenderLayer *rlp, *rl;
RenderPass *rpassp;
- int offs, partx, party;
+ int partx, party;
BLI_thread_lock(LOCK_IMAGE);
@@ -1120,13 +1102,6 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons
continue;
}
- if (rrpart->crop) { /* filters add pixel extra */
- offs = (rrpart->crop + rrpart->crop * rrpart->rectx);
- }
- else {
- offs = 0;
- }
-
/* passes are allocated in sync */
for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
const int xstride = rpassp->channels;
@@ -1141,13 +1116,13 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons
fullname,
xstride,
xstride * rrpart->rectx,
- rpassp->rect + a + xstride * offs);
+ rpassp->rect + a);
}
}
}
- party = rrpart->tilerect.ymin + rrpart->crop;
- partx = rrpart->tilerect.xmin + rrpart->crop;
+ party = rrpart->tilerect.ymin;
+ partx = rrpart->tilerect.xmin;
for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
rl = RE_GetRenderLayer(rr, rlp->name);
@@ -1267,7 +1242,7 @@ void render_result_exr_file_end(Render *re, RenderEngine *engine)
/* Create new render result in memory instead of on disk. */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
render_result_free_list(&re->fullresult, re->result);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
BLI_rw_mutex_unlock(&re->resultmutex);
LISTBASE_FOREACH (RenderLayer *, rl, &re->result->layers) {
@@ -1429,7 +1404,7 @@ bool render_result_exr_file_cache_read(Render *re)
char *root = U.render_cachedir;
RE_FreeRenderResult(re->result);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
/* First try cache. */
render_result_exr_file_cache_path(re->scene, root, str);
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index 5c487223e94..67edd075e24 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -51,7 +51,6 @@ extern "C" {
struct RenderResult *render_result_new(struct Render *re,
struct rcti *partrct,
- int crop,
int savebuffers,
const char *layername,
const char *viewname);
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index 11e213d842d..3a9c23de5cc 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -23,10 +23,15 @@
* \ingroup sequencer
*/
+#include "DNA_scene_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
+struct BlendDataReader;
+struct BlendLibReader;
+struct BlendWriter;
struct Depsgraph;
struct Editing;
struct GPUOffScreen;
@@ -47,6 +52,7 @@ struct bSound;
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
+struct SequencerToolSettings;
/* Wipe effect */
enum {
@@ -161,7 +167,7 @@ void SEQ_render_new_render_data(struct Main *bmain,
int preview_render_size,
int for_render,
SeqRenderData *r_context);
-int SEQ_render_evaluate_frame(struct Scene *scene, int timeline_frame);
+int SEQ_render_evaluate_frame(struct ListBase *seqbase, int timeline_frame);
struct StripElem *SEQ_render_give_stripelem(struct Sequence *seq, int timeline_frame);
/* **********************************************************************
@@ -179,9 +185,16 @@ void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4
* Sequencer scene functions
* ********************************************************************** */
+struct SequencerToolSettings *SEQ_tool_settings_init(void);
+void SEQ_tool_settings_free(struct SequencerToolSettings *tool_settings);
+eSeqImageFitMethod SEQ_tool_settings_fit_method_get(struct Scene *scene);
+void SEQ_tool_settings_fit_method_set(struct Scene *scene, eSeqImageFitMethod fit_method);
+
+struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSettings *tool_settings);
struct Editing *BKE_sequencer_editing_get(struct Scene *scene, bool alloc);
struct Editing *BKE_sequencer_editing_ensure(struct Scene *scene);
void BKE_sequencer_editing_free(struct Scene *scene, const bool do_id_user);
+struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed);
void BKE_sequencer_sort(struct Scene *scene);
struct Sequence *BKE_sequencer_from_elem(ListBase *seqbase, struct StripElem *se);
struct Sequence *BKE_sequencer_active_get(struct Scene *scene);
@@ -361,6 +374,20 @@ void BKE_sequence_invalidate_cache_in_range(struct Scene *scene,
void BKE_sequencer_all_free_anim_ibufs(struct Scene *scene, int timeline_frame);
/* **********************************************************************
+ * util.c
+ *
+ * Add strips
+ * **********************************************************************
+ */
+
+void SEQ_set_scale_to_fit(const struct Sequence *seq,
+ const int image_width,
+ const int image_height,
+ const int preview_width,
+ const int preview_height,
+ const eSeqImageFitMethod fit_method);
+
+/* **********************************************************************
* sequencer.c
*
* Add strips
@@ -376,6 +403,7 @@ typedef struct SeqLoadInfo {
int type;
int len; /* only for image strips */
char path[1024]; /* 1024 = FILE_MAX */
+ eSeqImageFitMethod fit_method;
/* multiview */
char views_format;
@@ -595,6 +623,33 @@ struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
struct Sequence *seq,
const int timeline_frame,
const eSeqSplitMethod method);
+bool SEQ_edit_remove_gaps(struct Scene *scene,
+ struct ListBase *seqbase,
+ const int initial_frame,
+ const bool remove_all_gaps);
+
+/* **********************************************************************
+ * strip_time.c
+ *
+ * Editing functions
+ * **********************************************************************
+ */
+
+void SEQ_timeline_boundbox(const struct Scene *scene,
+ const struct ListBase *seqbase,
+ struct rctf *rect);
+
+/* **********************************************************************
+ * strip_transform.c
+ *
+ * Editing functions
+ * **********************************************************************
+ */
+
+void SEQ_offset_after_frame(struct Scene *scene,
+ struct ListBase *seqbase,
+ const int delta,
+ const int timeline_frame);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h
index 58e0a97d4c5..6a94c0ea9d9 100644
--- a/source/blender/sequencer/intern/effects.h
+++ b/source/blender/sequencer/intern/effects.h
@@ -28,8 +28,8 @@ extern "C" {
#endif
struct Scene;
-struct Sequence;
struct SeqRenderData;
+struct Sequence;
/* **********************************************************************
* sequencer.c
diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h
index 0fcf0548628..2cb35670a2c 100644
--- a/source/blender/sequencer/intern/image_cache.h
+++ b/source/blender/sequencer/intern/image_cache.h
@@ -30,8 +30,8 @@ extern "C" {
struct ImBuf;
struct Main;
struct Scene;
-struct Sequence;
struct SeqRenderData;
+struct Sequence;
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h
index e1f998d18e2..bbc66c6f84c 100644
--- a/source/blender/sequencer/intern/multiview.h
+++ b/source/blender/sequencer/intern/multiview.h
@@ -27,14 +27,7 @@
extern "C" {
#endif
-struct Editing;
-struct ImBuf;
-struct Main;
-struct Mask;
struct Scene;
-struct Sequence;
-struct StripColorBalance;
-struct StripElem;
/* **********************************************************************
* sequencer.c
diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h
index aa47a9dbcfc..1633ee297f8 100644
--- a/source/blender/sequencer/intern/prefetch.h
+++ b/source/blender/sequencer/intern/prefetch.h
@@ -27,11 +27,9 @@
extern "C" {
#endif
-struct ImBuf;
-struct Main;
struct Scene;
-struct Sequence;
struct SeqRenderData;
+struct Sequence;
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/proxy.h b/source/blender/sequencer/intern/proxy.h
index a362a318a5a..a65fdcd42fe 100644
--- a/source/blender/sequencer/intern/proxy.h
+++ b/source/blender/sequencer/intern/proxy.h
@@ -27,10 +27,10 @@
extern "C" {
#endif
-struct anim;
struct ImBuf;
struct SeqRenderData;
struct Sequence;
+struct anim;
#define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE)
struct ImBuf *seq_proxy_fetch(const struct SeqRenderData *context,
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 008ea1cd3a0..2e757a06751 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -337,16 +337,17 @@ static int evaluate_seq_frame_gen(Sequence **seq_arr,
return totseq;
}
-int SEQ_render_evaluate_frame(Scene *scene, int timeline_frame)
+/**
+ * Count number of strips in timeline at timeline_frame
+ *
+ * \param seqbase: ListBase in which strips are located
+ * \param timeline_frame: frame on timeline from where gaps are searched for
+ * \return number of strips
+ */
+int SEQ_render_evaluate_frame(ListBase *seqbase, int timeline_frame)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq_arr[MAXSEQ + 1];
-
- if (ed == NULL) {
- return 0;
- }
-
- return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, timeline_frame, 0);
+ return evaluate_seq_frame_gen(seq_arr, seqbase, timeline_frame, 0);
}
static bool video_seq_is_rendered(Sequence *seq)
@@ -527,7 +528,6 @@ static void sequencer_image_transform_init(void *handle_v,
handle->ibuf_source = init_data->ibuf_source;
handle->ibuf_out = init_data->ibuf_out;
handle->transform = init_data->transform;
- handle->scale_to_fit = init_data->scale_to_fit;
handle->image_scale_factor = init_data->image_scale_factor;
handle->for_render = init_data->for_render;
@@ -539,8 +539,8 @@ static void *sequencer_image_transform_do_thread(void *data_v)
{
const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v;
const StripTransform *transform = data->transform;
- const float scale_x = transform->scale_x * data->scale_to_fit;
- const float scale_y = transform->scale_y * data->scale_to_fit;
+ const float scale_x = transform->scale_x * data->image_scale_factor;
+ const float scale_y = transform->scale_y * data->image_scale_factor;
const float scale_to_fit_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2;
const float scale_to_fit_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2;
const float translate_x = transform->xofs * data->image_scale_factor + scale_to_fit_offs_x;
@@ -625,10 +625,6 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
IMB_filtery(preprocessed_ibuf);
}
- /* Calculate scale factor, so image fits in preview area with original aspect ratio. */
- const float scale_to_fit_factor = MIN2((float)context->rectx / (float)ibuf->x,
- (float)context->recty / (float)ibuf->y);
-
/* Get scale factor if preview resolution doesn't match project resolution. */
float preview_scale_factor;
if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) {
@@ -647,10 +643,10 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
const int height = ibuf->y;
const StripCrop *c = seq->strip->crop;
- const int left = c->left / scale_to_fit_factor * preview_scale_factor;
- const int right = c->right / scale_to_fit_factor * preview_scale_factor;
- const int top = c->top / scale_to_fit_factor * preview_scale_factor;
- const int bottom = c->bottom / scale_to_fit_factor * preview_scale_factor;
+ const int left = c->left;
+ const int right = c->right;
+ const int top = c->top;
+ const int bottom = c->bottom;
const float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* Left. */
@@ -672,7 +668,6 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
init_data.ibuf_source = ibuf;
init_data.ibuf_out = preprocessed_ibuf;
init_data.transform = seq->strip->transform;
- init_data.scale_to_fit = scale_to_fit_factor;
init_data.image_scale_factor = preview_scale_factor;
init_data.for_render = context->for_render;
IMB_processor_apply_threaded(context->recty,
diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h
index d5affeb547b..46748415187 100644
--- a/source/blender/sequencer/intern/render.h
+++ b/source/blender/sequencer/intern/render.h
@@ -27,7 +27,6 @@
extern "C" {
#endif
-struct Editing;
struct ImBuf;
struct ListBase;
struct Scene;
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index c998886626c..87b608ef141 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -301,6 +301,46 @@ static void seq_new_fix_links_recursive(Sequence *seq)
}
}
}
+
+SequencerToolSettings *SEQ_tool_settings_init(void)
+{
+ SequencerToolSettings *tool_settings = MEM_callocN(sizeof(SequencerToolSettings),
+ "Sequencer tool settings");
+ tool_settings->fit_method = SEQ_SCALE_TO_FIT;
+ return tool_settings;
+}
+
+void SEQ_tool_settings_free(SequencerToolSettings *tool_settings)
+{
+ MEM_freeN(tool_settings);
+}
+
+eSeqImageFitMethod SEQ_tool_settings_fit_method_get(Scene *scene)
+{
+ const SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings;
+ return tool_settings->fit_method;
+}
+
+void SEQ_tool_settings_fit_method_set(Scene *scene, eSeqImageFitMethod fit_method)
+{
+ SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings;
+ tool_settings->fit_method = fit_method;
+}
+
+/**
+ * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
+ *
+ * \param ed: sequence editor data
+ * \return pointer to active seqbase. returns NULL if ed is NULL
+ */
+ListBase *SEQ_active_seqbase_get(const Editing *ed)
+{
+ if (ed == NULL) {
+ return NULL;
+ }
+
+ return ed->seqbasep;
+}
/** \} */
/* -------------------------------------------------------------------- */
@@ -609,4 +649,11 @@ static void seq_free_animdata(Scene *scene, Sequence *seq)
}
#undef SEQ_RNAPATH_MAXSTR
+
+SequencerToolSettings *SEQ_tool_settings_copy(SequencerToolSettings *tool_settings)
+{
+ SequencerToolSettings *tool_settings_copy = MEM_dupallocN(tool_settings);
+ return tool_settings_copy;
+}
+
/** \} */
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index d2e4025bdfc..e56dcf888a7 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -118,6 +118,16 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad
seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
+
+ char file_path[FILE_MAX];
+ BLI_join_dirfile(file_path, sizeof(file_path), seq_load->path, seq_load->name);
+ BLI_path_abs(file_path, BKE_main_blendfile_path(CTX_data_main(C)));
+ ImBuf *ibuf = IMB_loadiffname(file_path, IB_rect, seq->strip->colorspace_settings.name);
+ if (ibuf != NULL) {
+ SEQ_set_scale_to_fit(seq, ibuf->x, ibuf->y, scene->r.xsch, scene->r.ysch, seq_load->fit_method);
+ IMB_freeImBuf(ibuf);
+ }
+
BKE_sequence_invalidate_cache_composite(scene, seq);
return seq;
@@ -275,6 +285,11 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
IMB_anim_load_metadata(anim_arr[0]);
seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
+
+ const float width = IMB_anim_get_image_width(anim_arr[0]);
+ const float height = IMB_anim_get_image_height(anim_arr[0]);
+ SEQ_set_scale_to_fit(seq, width, height, scene->r.xsch, scene->r.ysch, seq_load->fit_method);
+
BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 3137a471470..a29810cc9ee 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -38,6 +38,8 @@
#include "BKE_scene.h"
#include "BKE_sound.h"
+#include "strip_time.h"
+
#include "SEQ_sequencer.h"
int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
@@ -319,3 +321,36 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
BKE_sequence_calc(scene, right_seq);
return right_seq;
}
+
+/**
+ * Find gap after initial_frame and move strips on right side to close the gap
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param initial_frame: frame on timeline from where gaps are searched for
+ * \param remove_all_gaps: remove all gaps instead of one gap
+ * \return true if gap is removed, otherwise false
+ */
+bool SEQ_edit_remove_gaps(Scene *scene,
+ ListBase *seqbase,
+ const int initial_frame,
+ const bool remove_all_gaps)
+{
+ GapInfo gap_info = {0};
+ seq_time_gap_info_get(scene, seqbase, initial_frame, &gap_info);
+
+ if (!gap_info.gap_exists) {
+ return false;
+ }
+
+ if (remove_all_gaps) {
+ while (gap_info.gap_exists) {
+ SEQ_offset_after_frame(scene, seqbase, -gap_info.gap_length, gap_info.gap_start_frame);
+ seq_time_gap_info_get(scene, seqbase, initial_frame, &gap_info);
+ }
+ }
+ else {
+ SEQ_offset_after_frame(scene, seqbase, -gap_info.gap_length, gap_info.gap_start_frame);
+ }
+ return true;
+}
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index a0ae6d6f16d..d9074b2a683 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -351,3 +351,85 @@ float BKE_sequence_get_fps(Scene *scene, Sequence *seq)
}
return 0.0f;
}
+
+/**
+ * Define boundary rectangle of sequencer timeline and fill in rect data
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: data structure describing rectangle, that will be filled in by this function
+ */
+void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
+{
+ rect->xmin = scene->r.sfra;
+ rect->xmax = scene->r.efra + 1;
+ rect->ymin = 0.0f;
+ rect->ymax = 8.0f;
+
+ if (seqbase == NULL) {
+ return;
+ }
+
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (rect->xmin > seq->startdisp - 1) {
+ rect->xmin = seq->startdisp - 1;
+ }
+ if (rect->xmax < seq->enddisp + 1) {
+ rect->xmax = seq->enddisp + 1;
+ }
+ if (rect->ymax < seq->machine + 2) {
+ rect->ymax = seq->machine + 2;
+ }
+ }
+}
+
+/**
+ * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param initial_frame: frame on timeline from where gaps are searched for
+ * \param r_gap_info: data structure describing gap, that will be filled in by this function
+ */
+void seq_time_gap_info_get(const Scene *scene,
+ ListBase *seqbase,
+ const int initial_frame,
+ GapInfo *r_gap_info)
+{
+ rctf rectf;
+ /* Get first and last frame. */
+ SEQ_timeline_boundbox(scene, seqbase, &rectf);
+ const int sfra = (int)rectf.xmin;
+ const int efra = (int)rectf.xmax;
+ int timeline_frame = initial_frame;
+ r_gap_info->gap_exists = false;
+
+ if (SEQ_render_evaluate_frame(seqbase, initial_frame) == 0) {
+ /* Search backward for gap_start_frame. */
+ for (; timeline_frame >= sfra; timeline_frame--) {
+ if (SEQ_render_evaluate_frame(seqbase, timeline_frame) != 0) {
+ break;
+ }
+ }
+ r_gap_info->gap_start_frame = timeline_frame + 1;
+ timeline_frame = initial_frame;
+ }
+ else {
+ /* Search forward for gap_start_frame. */
+ for (; timeline_frame <= efra; timeline_frame++) {
+ if (SEQ_render_evaluate_frame(seqbase, timeline_frame) == 0) {
+ r_gap_info->gap_start_frame = timeline_frame;
+ break;
+ }
+ }
+ }
+ /* Search forward for gap_end_frame. */
+ for (; timeline_frame <= efra; timeline_frame++) {
+ if (SEQ_render_evaluate_frame(seqbase, timeline_frame) != 0) {
+ const int gap_end_frame = timeline_frame;
+ r_gap_info->gap_length = gap_end_frame - r_gap_info->gap_start_frame;
+ r_gap_info->gap_exists = true;
+ break;
+ }
+ }
+}
diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h
index e4fb7f1d2ec..ca9a935bc96 100644
--- a/source/blender/sequencer/intern/strip_time.h
+++ b/source/blender/sequencer/intern/strip_time.h
@@ -27,12 +27,24 @@
extern "C" {
#endif
+struct ListBase;
struct Scene;
struct Sequence;
float seq_give_frame_index(struct Sequence *seq, float timeline_frame);
void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq);
+/* Describes gap between strips in timeline. */
+typedef struct GapInfo {
+ int gap_start_frame; /* Start frame of the gap. */
+ int gap_length; /* Length of the gap. */
+ bool gap_exists; /* False if there are no gaps. */
+} GapInfo;
+void seq_time_gap_info_get(const struct Scene *scene,
+ struct ListBase *seqbase,
+ const int initial_frame,
+ struct GapInfo *r_gap_info);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 233f8e5b22e..4aabe87bce1 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -397,3 +397,33 @@ bool BKE_sequence_base_shuffle_time(ListBase *seqbasep,
return offset ? false : true;
}
+
+/**
+ * Move strips and markers (if not locked) that start after timeline_frame by delta frames
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param delta: offset in frames to be applied
+ * \param timeline_frame: frame on timeline from where strips are moved
+ */
+void SEQ_offset_after_frame(Scene *scene,
+ ListBase *seqbase,
+ const int delta,
+ const int timeline_frame)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (seq->startdisp >= timeline_frame) {
+ BKE_sequence_translate(scene, seq, delta);
+ BKE_sequence_calc(scene, seq);
+ BKE_sequence_invalidate_cache_preprocessed(scene, seq);
+ }
+ }
+
+ if (!scene->toolsettings->lock_markers) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
+ if (marker->frame >= timeline_frame) {
+ marker->frame += delta;
+ }
+ }
+ }
+}
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index 2b1d36a7709..ab0b65dba7f 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -36,6 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_utildefines.h"
#include "BKE_image.h"
#include "BKE_main.h"
@@ -547,3 +548,36 @@ bool sequencer_seq_generates_image(Sequence *seq)
}
return false;
}
+
+void SEQ_set_scale_to_fit(const Sequence *seq,
+ const int image_width,
+ const int image_height,
+ const int preview_width,
+ const int preview_height,
+ const eSeqImageFitMethod fit_method)
+{
+ StripTransform *transform = seq->strip->transform;
+
+ switch (fit_method) {
+ case SEQ_SCALE_TO_FIT:
+ transform->scale_x = transform->scale_y = MIN2((float)preview_width / (float)image_width,
+ (float)preview_height / (float)image_height);
+
+ break;
+ case SEQ_SCALE_TO_FILL:
+
+ transform->scale_x = transform->scale_y = MAX2((float)preview_width / (float)image_width,
+ (float)preview_height / (float)image_height);
+ break;
+ case SEQ_STRETCH_TO_FILL:
+ transform->scale_x = (float)preview_width / (float)image_width;
+ transform->scale_y = (float)preview_height / (float)image_height;
+ break;
+ case SEQ_USE_ORIGINAL_SIZE:
+ transform->scale_x = 1.0f;
+ transform->scale_y = 1.0f;
+ break;
+ }
+
+ return;
+}
diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h
index fe6041ec5e8..f30ea753d37 100644
--- a/source/blender/sequencer/intern/utils.h
+++ b/source/blender/sequencer/intern/utils.h
@@ -28,7 +28,6 @@ extern "C" {
#endif
struct Scene;
-struct anim;
bool sequencer_seq_generates_image(struct Sequence *seq);
void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index ac27862d507..c1ae307eb55 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1204,7 +1204,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
RNA_STRUCT_END;
}
else {
- LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) {
+ LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, NULL);
@@ -2293,6 +2293,11 @@ static int wm_handler_fileselect_do(bContext *C,
}
wm_handler_op_context(C, handler, ctx_win->eventstate);
+ ScrArea *handler_area = CTX_wm_area(C);
+ /* Make sure new context area is ready, the operator callback may operate on it. */
+ if (handler_area) {
+ ED_area_do_refresh(C, handler_area);
+ }
/* Needed for #UI_popup_menu_reports. */
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index baa47098bd3..c26acfc9802 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -23,7 +23,6 @@
#pragma once
-struct ARegion;
struct ReportList;
struct wmWindow;