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:
authorJames Monteath <james@blender.org>2021-06-01 16:07:46 +0300
committerJeroen Bakker <jeroen@blender.org>2021-06-01 16:18:11 +0300
commit8a63466ca3380479a92a65b670a074277d9a8671 (patch)
treece89d6a394431a36770de9bb4421a41962862194
parentee54a8ace753a56236f5d1d647da7a40904af6b3 (diff)
parent6899dcab5339d1f17dd2ea665a38e4ab28ab23fc (diff)
BuildBot: Cleanup
Removing scripts that were placed in the source tree that would drive the old buildbot. With the new buildbot in place these scripts aren't being used anymore. The buildbit is currently driven by `build_files/config/pipeline_config.json`. In the near future make update would also use this config. Overview of the new buildbot: https://wiki.blender.org/wiki/Infrastructure/BuildBot Work done by James Monteath.
-rw-r--r--build_files/cmake/platform/platform_win32.cmake6
-rw-r--r--doc/python_api/sphinx_doc_gen.py4
-rw-r--r--intern/cycles/blender/blender_camera.cpp27
-rw-r--r--intern/cycles/blender/blender_session.cpp13
-rw-r--r--intern/cycles/blender/blender_sync.h3
-rw-r--r--intern/cycles/render/geometry.cpp2
-rw-r--r--intern/cycles/util/util_task.h4
-rw-r--r--intern/ffmpeg/ffmpeg_compat.h49
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp73
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp35
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h168
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/startup/bl_operators/userpref.py2
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py2
-rw-r--r--release/scripts/startup/bl_ui/space_node.py4
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py12
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--release/windows/manifest/blender.exe.manifest.in6
-rw-r--r--source/blender/blenfont/intern/blf_font_win32_compat.c6
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h6
-rw-r--r--source/blender/blenkernel/BKE_node.h12
-rw-r--r--source/blender/blenkernel/intern/collection.c3
-rw-r--r--source/blender/blenkernel/intern/customdata_file.c8
-rw-r--r--source/blender/blenkernel/intern/editmesh.c3
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc26
-rw-r--r--source/blender/blenkernel/intern/lib_id.c30
-rw-r--r--source/blender/blenkernel/intern/lib_id_test.cc60
-rw-r--r--source/blender/blenkernel/intern/lib_override.c125
-rw-r--r--source/blender/blenkernel/intern/node.cc1
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c191
-rw-r--r--source/blender/blenlib/BLI_mpq3.hh16
-rw-r--r--source/blender/blenlib/intern/fileops.c4
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc182
-rw-r--r--source/blender/blenlib/intern/mesh_intersect.cc91
-rw-r--r--source/blender/blenloader/intern/versioning_250.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c53
-rw-r--r--source/blender/bmesh/CMakeLists.txt10
-rw-r--r--source/blender/bmesh/bmesh.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.c305
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.h24
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c289
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h3
-rw-r--r--source/blender/compositor/CMakeLists.txt12
-rw-r--r--source/blender/compositor/COM_defines.h10
-rw-r--r--source/blender/compositor/intern/COM_BufferOperation.cc65
-rw-r--r--source/blender/compositor/intern/COM_BufferOperation.h37
-rw-r--r--source/blender/compositor/intern/COM_CPUDevice.cc23
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.cc18
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.h5
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc37
-rw-r--r--source/blender/compositor/intern/COM_Debug.h2
-rw-r--r--source/blender/compositor/intern/COM_Enums.h15
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cc1
-rw-r--r--source/blender/compositor/intern/COM_ExecutionModel.cc48
-rw-r--r--source/blender/compositor/intern/COM_ExecutionModel.h84
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc143
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h25
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.cc327
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.h89
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedOperation.cc26
-rw-r--r--source/blender/compositor/intern/COM_MultiThreadedOperation.h73
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.cc176
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h66
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc12
-rw-r--r--source/blender/compositor/intern/COM_SharedOperationBuffers.cc128
-rw-r--r--source/blender/compositor/intern/COM_SharedOperationBuffers.h70
-rw-r--r--source/blender/compositor/intern/COM_TiledExecutionModel.cc158
-rw-r--r--source/blender/compositor/intern/COM_TiledExecutionModel.h54
-rw-r--r--source/blender/compositor/intern/COM_WorkPackage.h13
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cc13
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.h2
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc8
-rw-r--r--source/blender/compositor/nodes/COM_TranslateNode.cc5
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc17
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.h2
-rw-r--r--source/blender/draw/CMakeLists.txt4
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl6
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl4
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h39
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc996
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_extractors.c (renamed from source/blender/draw/intern/draw_cache_extract_mesh.c)3381
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_private.h515
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.c372
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc6
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c45
-rw-r--r--source/blender/draw/intern/draw_cache_inline.h4
-rw-r--r--source/blender/draw/intern/draw_hair.c4
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl2
-rw-r--r--source/blender/editors/curve/editcurve_paint.c2
-rw-r--r--source/blender/editors/include/ED_uvedit.h1
-rw-r--r--source/blender/editors/include/ED_view3d.h17
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c100
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c6
-rw-r--r--source/blender/editors/object/object_remesh.c4
-rw-r--r--source/blender/editors/object/object_transform.c4
-rw-r--r--source/blender/editors/physics/particle_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h2
-rw-r--r--source/blender/editors/space_node/drawnode.c5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c15
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c20
-rw-r--r--source/blender/gpu/GPU_matrix.h36
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc47
-rw-r--r--source/blender/imbuf/intern/indexer.c46
-rw-r--r--source/blender/makesdna/DNA_node_types.h9
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h1
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_access.c16
-rw-r--r--source/blender/makesrna/intern/rna_color.c2
-rw-r--r--source/blender/makesrna/intern/rna_curve.c4
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c30
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c5
-rw-r--r--source/blender/makesrna/intern/rna_space.c2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c8
-rw-r--r--source/blender/modifiers/CMakeLists.txt6
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc5
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c16
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_geometry.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc124
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc318
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc44
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c7
-rw-r--r--source/blender/python/intern/bpy_app.c5
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c5
-rw-r--r--source/blender/sequencer/intern/image_cache.c4
-rw-r--r--source/blender/sequencer/intern/render.c6
-rw-r--r--source/blender/sequencer/intern/strip_add.c13
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c4
-rw-r--r--source/creator/CMakeLists.txt4
-rw-r--r--source/creator/creator_args.c3
m---------source/tools0
146 files changed, 6297 insertions, 3706 deletions
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index b6ec016aa95..497fd179aaf 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -119,7 +119,7 @@ string(APPEND CMAKE_MODULE_LINKER_FLAGS " /SAFESEH:NO /ignore:4099")
list(APPEND PLATFORM_LINKLIBS
ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 Comctl32 version
advapi32 shfolder shell32 ole32 oleaut32 uuid psapi Dbghelp Shlwapi
- pathcch
+ pathcch Shcore
)
if(WITH_INPUT_IME)
@@ -144,8 +144,8 @@ add_definitions(-D_ALLOW_KEYWORD_MACROS)
# that both /GR and /GR- are specified.
remove_cc_flag("/GR")
-# We want to support Windows 7 level ABI
-add_definitions(-D_WIN32_WINNT=0x601)
+# Make the Windows 8.1 API available for use.
+add_definitions(-D_WIN32_WINNT=0x603)
include(build_files/cmake/platform/platform_win32_bundle_crt.cmake)
remove_cc_flag("/MDd" "/MD" "/Zi")
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 032f8a86bd5..4be27e0f0e8 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -954,7 +954,7 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
# constant, not much fun we can do here except to list it.
# TODO, figure out some way to document these!
fw(".. data:: %s\n\n" % attribute)
- write_indented_lines(" ", fw, "constant value %s" % repr(value), False)
+ write_indented_lines(" ", fw, "Constant value %s" % repr(value), False)
fw("\n")
else:
BPY_LOGGER.debug("\tnot documenting %s.%s of %r type" % (module_name, attribute, value_type.__name__))
@@ -1246,7 +1246,7 @@ def pyrna_enum2sphinx(prop, use_empty_descriptions=False):
"%s.\n" % (
identifier,
# Account for multi-line enum descriptions, allowing this to be a block of text.
- indent(", ".join(escape_rst(val) for val in (name, description) if val) or "Undocumented", " "),
+ indent(" -- ".join(escape_rst(val) for val in (name, description) if val) or "Undocumented", " "),
)
for identifier, name, description in prop.enum_items
])
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index b31841801d8..6954c5c2f26 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -83,6 +83,8 @@ struct BlenderCamera {
BoundBox2D pano_viewplane;
BoundBox2D viewport_camera_border;
+ float passepartout_alpha;
+
Transform matrix;
float offscreen_dicing_scale;
@@ -125,6 +127,7 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings &b_rende
bcam->pano_viewplane.top = 1.0f;
bcam->viewport_camera_border.right = 1.0f;
bcam->viewport_camera_border.top = 1.0f;
+ bcam->passepartout_alpha = 0.5f;
bcam->offscreen_dicing_scale = 1.0f;
bcam->matrix = transform_identity();
@@ -212,6 +215,8 @@ static void blender_camera_from_object(BlenderCamera *bcam,
bcam->lens = b_camera.lens();
+ bcam->passepartout_alpha = b_camera.show_passepartout() ? b_camera.passepartout_alpha() : 0.0f;
+
if (b_camera.dof().use_dof()) {
/* allow f/stop number to change aperture_size but still
* give manual control over aperture radius */
@@ -834,15 +839,19 @@ static void blender_camera_border(BlenderCamera *bcam,
full_border,
&bcam->viewport_camera_border);
- if (!b_render.use_border()) {
+ if (b_render.use_border()) {
+ bcam->border.left = b_render.border_min_x();
+ bcam->border.right = b_render.border_max_x();
+ bcam->border.bottom = b_render.border_min_y();
+ bcam->border.top = b_render.border_max_y();
+ }
+ else if (bcam->passepartout_alpha == 1.0f) {
+ bcam->border = full_border;
+ }
+ else {
return;
}
- bcam->border.left = b_render.border_min_x();
- bcam->border.right = b_render.border_max_x();
- bcam->border.bottom = b_render.border_min_y();
- bcam->border.top = b_render.border_max_y();
-
/* Determine viewport subset matching camera border. */
blender_camera_border_subset(b_engine,
b_render,
@@ -885,8 +894,7 @@ void BlenderSync::sync_view(BL::SpaceView3D &b_v3d,
}
}
-BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render,
- BL::SpaceView3D &b_v3d,
+BufferParams BlenderSync::get_buffer_params(BL::SpaceView3D &b_v3d,
BL::RegionView3D &b_rv3d,
Camera *cam,
int width,
@@ -902,7 +910,8 @@ BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render,
if (b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA)
use_border = b_v3d.use_render_border();
else
- use_border = b_render.use_border();
+ /* the camera can always have a passepartout */
+ use_border = true;
if (use_border) {
/* border render */
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 89854f6a0e5..29de886e4ff 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -155,7 +155,7 @@ void BlenderSession::create_session()
/* set buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
+ b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
@@ -242,8 +242,7 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render,
- b_null_space_view3d,
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_null_space_view3d,
b_null_region_view3d,
scene->camera,
width,
@@ -486,7 +485,7 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background, b_view_layer);
BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
+ b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
/* temporary render result to find needed passes and views */
BL::RenderResult b_rr = begin_render_result(
@@ -810,7 +809,7 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
/* get buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
+ b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
if (!buffer_params.denoising_data_pass) {
session_params.denoising.use = false;
@@ -889,7 +888,7 @@ bool BlenderSession::draw(int w, int h)
SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_render, b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
+ b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
bool session_pause = BlenderSync::get_session_pause(b_scene, background);
if (session_pause == false) {
@@ -907,7 +906,7 @@ bool BlenderSession::draw(int w, int h)
/* draw */
BufferParams buffer_params = BlenderSync::get_buffer_params(
- b_render, b_v3d, b_rv3d, scene->camera, width, height, session->params.denoising.use);
+ b_v3d, b_rv3d, scene->camera, width, height, session->params.denoising.use);
DeviceDrawParams draw_params;
if (session->params.display_buffer_linear) {
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 8cd65f13f70..1c98e529190 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -104,8 +104,7 @@ class BlenderSync {
bool background,
BL::ViewLayer b_view_layer = BL::ViewLayer(PointerRNA_NULL));
static bool get_session_pause(BL::Scene &b_scene, bool background);
- static BufferParams get_buffer_params(BL::RenderSettings &b_render,
- BL::SpaceView3D &b_v3d,
+ static BufferParams get_buffer_params(BL::SpaceView3D &b_v3d,
BL::RegionView3D &b_rv3d,
Camera *cam,
int width,
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 1c4b360750f..ce76658acb6 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -2063,7 +2063,7 @@ void GeometryManager::device_update(Device *device,
* for meshes with correct bounding boxes.
*
* This wouldn't cause wrong results, just true
- * displacement might be less optimal ot calculate.
+ * displacement might be less optimal to calculate.
*/
scene->object_manager->need_flags_update = old_need_object_flags_update;
}
diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h
index 7c39ed675b5..906bf420756 100644
--- a/intern/cycles/util/util_task.h
+++ b/intern/cycles/util/util_task.h
@@ -32,7 +32,7 @@ typedef function<void(void)> TaskRunFunction;
/* Task Pool
*
- * Pool of tasks that will be executed by the central TaskScheduler.For each
+ * Pool of tasks that will be executed by the central TaskScheduler. For each
* pool, we can wait for all tasks to be done, or cancel them before they are
* done.
*
@@ -77,7 +77,7 @@ class TaskPool {
/* Task Scheduler
*
- * Central scheduler that holds running threads ready to execute tasks. A singe
+ * Central scheduler that holds running threads ready to execute tasks. A single
* queue holds the task from all pools. */
class TaskScheduler {
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index 54a004d53e2..0c22cf82688 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -43,6 +43,55 @@
# define FFMPEG_INLINE static inline
#endif
+#if (LIBAVFORMAT_VERSION_MAJOR < 58) || \
+ ((LIBAVFORMAT_VERSION_MAJOR == 58) && (LIBAVFORMAT_VERSION_MINOR < 76))
+# define FFMPEG_USE_DURATION_WORKAROUND 1
+
+/* Before ffmpeg 4.4, package duration calculation used depricated variables to calculate the
+ * packet duration. Use the function from commit
+ * github.com/FFmpeg/FFmpeg/commit/1c0885334dda9ee8652e60c586fa2e3674056586
+ * to calculate the correct framerate for ffmpeg < 4.4.
+ */
+
+FFMPEG_INLINE
+void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
+{
+ if (pkt->duration < 0 && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+ av_log(s,
+ AV_LOG_WARNING,
+ "Packet with invalid duration %" PRId64 " in stream %d\n",
+ pkt->duration,
+ pkt->stream_index);
+ pkt->duration = 0;
+ }
+
+ if (pkt->duration) {
+ return;
+ }
+
+ switch (st->codecpar->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) {
+ pkt->duration = av_rescale_q(1, av_inv_q(st->avg_frame_rate), st->time_base);
+ }
+ else if (st->time_base.num * 1000LL > st->time_base.den) {
+ pkt->duration = 1;
+ }
+ break;
+ case AVMEDIA_TYPE_AUDIO: {
+ int frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size);
+ if (frame_size && st->codecpar->sample_rate) {
+ pkt->duration = av_rescale_q(
+ frame_size, (AVRational){1, st->codecpar->sample_rate}, st->time_base);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+#endif
+
FFMPEG_INLINE
void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
{
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 38dea9c1142..fc3cb81e26a 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -32,6 +32,7 @@
#include <commctrl.h>
#include <psapi.h>
#include <shellapi.h>
+#include <shellscalingapi.h>
#include <shlobj.h>
#include <tlhelp32.h>
#include <windowsx.h>
@@ -97,41 +98,6 @@
# define VK_GR_LESS 0xE2
#endif // VK_GR_LESS
-#ifndef VK_MEDIA_NEXT_TRACK
-# define VK_MEDIA_NEXT_TRACK 0xB0
-#endif // VK_MEDIA_NEXT_TRACK
-#ifndef VK_MEDIA_PREV_TRACK
-# define VK_MEDIA_PREV_TRACK 0xB1
-#endif // VK_MEDIA_PREV_TRACK
-#ifndef VK_MEDIA_STOP
-# define VK_MEDIA_STOP 0xB2
-#endif // VK_MEDIA_STOP
-#ifndef VK_MEDIA_PLAY_PAUSE
-# define VK_MEDIA_PLAY_PAUSE 0xB3
-#endif // VK_MEDIA_PLAY_PAUSE
-
-// Window message newer than Windows 7
-#ifndef WM_DPICHANGED
-# define WM_DPICHANGED 0x02E0
-#endif // WM_DPICHANGED
-
-// WM_POINTER API messages minimum Windows 7
-#ifndef WM_POINTERENTER
-# define WM_POINTERENTER 0x0249
-#endif // WM_POINTERENTER
-#ifndef WM_POINTERDOWN
-# define WM_POINTERDOWN 0x0246
-#endif // WM_POINTERDOWN
-#ifndef WM_POINTERUPDATE
-# define WM_POINTERUPDATE 0x0245
-#endif // WM_POINTERUPDATE
-#ifndef WM_POINTERUP
-# define WM_POINTERUP 0x0247
-#endif // WM_POINTERUP
-#ifndef WM_POINTERLEAVE
-# define WM_POINTERLEAVE 0x024A
-#endif // WM_POINTERLEAVE
-
/* Workaround for some laptop touchpads, some of which seems to
* have driver issues which makes it so window function receives
* the message, but PeekMessage doesn't pick those messages for
@@ -173,24 +139,6 @@ static void initRawInput()
#undef DEVICE_COUNT
}
-#ifndef DPI_ENUMS_DECLARED
-typedef enum PROCESS_DPI_AWARENESS {
- PROCESS_DPI_UNAWARE = 0,
- PROCESS_SYSTEM_DPI_AWARE = 1,
- PROCESS_PER_MONITOR_DPI_AWARE = 2
-} PROCESS_DPI_AWARENESS;
-
-typedef enum MONITOR_DPI_TYPE {
- MDT_EFFECTIVE_DPI = 0,
- MDT_ANGULAR_DPI = 1,
- MDT_RAW_DPI = 2,
- MDT_DEFAULT = MDT_EFFECTIVE_DPI
-} MONITOR_DPI_TYPE;
-
-# define USER_DEFAULT_SCREEN_DPI 96
-
-# define DPI_ENUMS_DECLARED
-#endif
typedef HRESULT(API *GHOST_WIN32_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
typedef BOOL(API *GHOST_WIN32_EnableNonClientDpiScaling)(HWND);
@@ -205,15 +153,7 @@ GHOST_SystemWin32::GHOST_SystemWin32()
// Tell Windows we are per monitor DPI aware. This disables the default
// blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI.
- HMODULE m_shcore = ::LoadLibrary("Shcore.dll");
- if (m_shcore) {
- GHOST_WIN32_SetProcessDpiAwareness fpSetProcessDpiAwareness =
- (GHOST_WIN32_SetProcessDpiAwareness)::GetProcAddress(m_shcore, "SetProcessDpiAwareness");
-
- if (fpSetProcessDpiAwareness) {
- fpSetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
- }
- }
+ SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
// Check if current keyboard layout uses AltGr and save keylayout ID for
// specialized handling if keys like VK_OEM_*. I.e. french keylayout
@@ -581,14 +521,7 @@ GHOST_TSuccess GHOST_SystemWin32::init()
InitCommonControls();
/* Disable scaling on high DPI displays on Vista */
- HMODULE
- user32 = ::LoadLibraryA("user32.dll");
- typedef BOOL(WINAPI * LPFNSETPROCESSDPIAWARE)();
- LPFNSETPROCESSDPIAWARE SetProcessDPIAware = (LPFNSETPROCESSDPIAWARE)GetProcAddress(
- user32, "SetProcessDPIAware");
- if (SetProcessDPIAware)
- SetProcessDPIAware();
- FreeLibrary(user32);
+ SetProcessDPIAware();
initRawInput();
m_lfstart = ::GetTickCount();
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 3af92153e8b..eeafe333633 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -84,9 +84,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_wantAlphaBackground(alphaBackground),
m_normal_state(GHOST_kWindowStateNormal),
m_user32(NULL),
- m_fpGetPointerInfoHistory(NULL),
- m_fpGetPointerPenInfoHistory(NULL),
- m_fpGetPointerTouchInfoHistory(NULL),
m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : HWND_DESKTOP),
m_debug_context(is_debug)
{
@@ -153,19 +150,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_user32 = ::LoadLibrary("user32.dll");
if (m_hWnd) {
- if (m_user32) {
- // Touch enabled screens with pen support by default have gestures
- // enabled, which results in a delay between the pointer down event
- // and the first move when using the stylus. RegisterTouchWindow
- // disables the new gesture architecture enabling the events to be
- // sent immediately to the application rather than being absorbed by
- // the gesture API.
- GHOST_WIN32_RegisterTouchWindow pRegisterTouchWindow = (GHOST_WIN32_RegisterTouchWindow)
- GetProcAddress(m_user32, "RegisterTouchWindow");
- if (pRegisterTouchWindow) {
- pRegisterTouchWindow(m_hWnd, 0);
- }
- }
+ RegisterTouchWindow(m_hWnd, 0);
// Register this window as a droptarget. Requires m_hWnd to be valid.
// Note that OleInitialize(0) has to be called prior to this. Done in GHOST_SystemWin32.
@@ -232,16 +217,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
}
}
- // Initialize Windows Ink
- if (m_user32) {
- m_fpGetPointerInfoHistory = (GHOST_WIN32_GetPointerInfoHistory)::GetProcAddress(
- m_user32, "GetPointerInfoHistory");
- m_fpGetPointerPenInfoHistory = (GHOST_WIN32_GetPointerPenInfoHistory)::GetProcAddress(
- m_user32, "GetPointerPenInfoHistory");
- m_fpGetPointerTouchInfoHistory = (GHOST_WIN32_GetPointerTouchInfoHistory)::GetProcAddress(
- m_user32, "GetPointerTouchInfoHistory");
- }
-
// Initialize Wintab
m_wintab.handle = ::LoadLibrary("Wintab32.dll");
if (m_wintab.handle && m_system->getTabletAPI() != GHOST_kTabletNative) {
@@ -326,9 +301,6 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
if (m_user32) {
FreeLibrary(m_user32);
m_user32 = NULL;
- m_fpGetPointerInfoHistory = NULL;
- m_fpGetPointerPenInfoHistory = NULL;
- m_fpGetPointerTouchInfoHistory = NULL;
}
if (m_customCursor) {
@@ -950,15 +922,14 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
GHOST_TUns32 outCount;
- if (!(m_fpGetPointerInfoHistory && m_fpGetPointerInfoHistory(pointerId, &outCount, NULL))) {
+ if (!(GetPointerInfoHistory(pointerId, &outCount, NULL))) {
return GHOST_kFailure;
}
auto pointerPenInfo = std::vector<POINTER_PEN_INFO>(outCount);
outPointerInfo.resize(outCount);
- if (!(m_fpGetPointerPenInfoHistory &&
- m_fpGetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) {
+ if (!(GetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) {
return GHOST_kFailure;
}
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index b004f7e7b19..a13bd876667 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -53,177 +53,12 @@ typedef BOOL(API *GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID);
typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL);
typedef BOOL(API *GHOST_WIN32_WTOverlap)(HCTX, BOOL);
-// typedef to user32 functions to disable gestures on windows
-typedef BOOL(API *GHOST_WIN32_RegisterTouchWindow)(HWND hwnd, ULONG ulFlags);
-
// typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions
typedef UINT(API *GHOST_WIN32_GetDpiForWindow)(HWND);
#ifndef USER_DEFAULT_SCREEN_DPI
# define USER_DEFAULT_SCREEN_DPI 96
#endif // USER_DEFAULT_SCREEN_DPI
-// typedefs for user32 functions to allow pointer functions
-enum tagPOINTER_INPUT_TYPE {
- PT_POINTER = 1, // Generic pointer
- PT_TOUCH = 2, // Touch
- PT_PEN = 3, // Pen
- PT_MOUSE = 4, // Mouse
-#if (WINVER >= 0x0603)
- PT_TOUCHPAD = 5, // Touchpad
-#endif /* WINVER >= 0x0603 */
-};
-
-typedef enum tagPOINTER_BUTTON_CHANGE_TYPE {
- POINTER_CHANGE_NONE,
- POINTER_CHANGE_FIRSTBUTTON_DOWN,
- POINTER_CHANGE_FIRSTBUTTON_UP,
- POINTER_CHANGE_SECONDBUTTON_DOWN,
- POINTER_CHANGE_SECONDBUTTON_UP,
- POINTER_CHANGE_THIRDBUTTON_DOWN,
- POINTER_CHANGE_THIRDBUTTON_UP,
- POINTER_CHANGE_FOURTHBUTTON_DOWN,
- POINTER_CHANGE_FOURTHBUTTON_UP,
- POINTER_CHANGE_FIFTHBUTTON_DOWN,
- POINTER_CHANGE_FIFTHBUTTON_UP,
-} POINTER_BUTTON_CHANGE_TYPE;
-
-typedef DWORD POINTER_INPUT_TYPE;
-typedef UINT32 POINTER_FLAGS;
-
-#define POINTER_FLAG_NONE 0x00000000
-#define POINTER_FLAG_NEW 0x00000001
-#define POINTER_FLAG_INRANGE 0x00000002
-#define POINTER_FLAG_INCONTACT 0x00000004
-#define POINTER_FLAG_FIRSTBUTTON 0x00000010
-#define POINTER_FLAG_SECONDBUTTON 0x00000020
-#define POINTER_FLAG_THIRDBUTTON 0x00000040
-#define POINTER_FLAG_FOURTHBUTTON 0x00000080
-#define POINTER_FLAG_FIFTHBUTTON 0x00000100
-#define POINTER_FLAG_PRIMARY 0x00002000
-#define POINTER_FLAG_CONFIDENCE 0x000004000
-#define POINTER_FLAG_CANCELED 0x000008000
-#define POINTER_FLAG_DOWN 0x00010000
-#define POINTER_FLAG_UPDATE 0x00020000
-#define POINTER_FLAG_UP 0x00040000
-#define POINTER_FLAG_WHEEL 0x00080000
-#define POINTER_FLAG_HWHEEL 0x00100000
-#define POINTER_FLAG_CAPTURECHANGED 0x00200000
-#define POINTER_FLAG_HASTRANSFORM 0x00400000
-
-typedef struct tagPOINTER_INFO {
- POINTER_INPUT_TYPE pointerType;
- UINT32 pointerId;
- UINT32 frameId;
- POINTER_FLAGS pointerFlags;
- HANDLE sourceDevice;
- HWND hwndTarget;
- POINT ptPixelLocation;
- POINT ptHimetricLocation;
- POINT ptPixelLocationRaw;
- POINT ptHimetricLocationRaw;
- DWORD dwTime;
- UINT32 historyCount;
- INT32 InputData;
- DWORD dwKeyStates;
- UINT64 PerformanceCount;
- POINTER_BUTTON_CHANGE_TYPE ButtonChangeType;
-} POINTER_INFO;
-
-typedef UINT32 PEN_FLAGS;
-#define PEN_FLAG_NONE 0x00000000 // Default
-#define PEN_FLAG_BARREL 0x00000001 // The barrel button is pressed
-#define PEN_FLAG_INVERTED 0x00000002 // The pen is inverted
-#define PEN_FLAG_ERASER 0x00000004 // The eraser button is pressed
-
-typedef UINT32 PEN_MASK;
-#define PEN_MASK_NONE 0x00000000 // Default - none of the optional fields are valid
-#define PEN_MASK_PRESSURE 0x00000001 // The pressure field is valid
-#define PEN_MASK_ROTATION 0x00000002 // The rotation field is valid
-#define PEN_MASK_TILT_X 0x00000004 // The tiltX field is valid
-#define PEN_MASK_TILT_Y 0x00000008 // The tiltY field is valid
-
-typedef struct tagPOINTER_PEN_INFO {
- POINTER_INFO pointerInfo;
- PEN_FLAGS penFlags;
- PEN_MASK penMask;
- UINT32 pressure;
- UINT32 rotation;
- INT32 tiltX;
- INT32 tiltY;
-} POINTER_PEN_INFO;
-
-/*
- * Flags that appear in pointer input message parameters
- */
-#define POINTER_MESSAGE_FLAG_NEW 0x00000001 // New pointer
-#define POINTER_MESSAGE_FLAG_INRANGE 0x00000002 // Pointer has not departed
-#define POINTER_MESSAGE_FLAG_INCONTACT 0x00000004 // Pointer is in contact
-#define POINTER_MESSAGE_FLAG_FIRSTBUTTON 0x00000010 // Primary action
-#define POINTER_MESSAGE_FLAG_SECONDBUTTON 0x00000020 // Secondary action
-#define POINTER_MESSAGE_FLAG_THIRDBUTTON 0x00000040 // Third button
-#define POINTER_MESSAGE_FLAG_FOURTHBUTTON 0x00000080 // Fourth button
-#define POINTER_MESSAGE_FLAG_FIFTHBUTTON 0x00000100 // Fifth button
-#define POINTER_MESSAGE_FLAG_PRIMARY 0x00002000 // Pointer is primary
-#define POINTER_MESSAGE_FLAG_CONFIDENCE \
- 0x00004000 // Pointer is considered unlikely to be accidental
-#define POINTER_MESSAGE_FLAG_CANCELED 0x00008000 // Pointer is departing in an abnormal manner
-
-typedef UINT32 TOUCH_FLAGS;
-#define TOUCH_FLAG_NONE 0x00000000 // Default
-
-typedef UINT32 TOUCH_MASK;
-#define TOUCH_MASK_NONE 0x00000000 // Default - none of the optional fields are valid
-#define TOUCH_MASK_CONTACTAREA 0x00000001 // The rcContact field is valid
-#define TOUCH_MASK_ORIENTATION 0x00000002 // The orientation field is valid
-#define TOUCH_MASK_PRESSURE 0x00000004 // The pressure field is valid
-
-typedef struct tagPOINTER_TOUCH_INFO {
- POINTER_INFO pointerInfo;
- TOUCH_FLAGS touchFlags;
- TOUCH_MASK touchMask;
- RECT rcContact;
- RECT rcContactRaw;
- UINT32 orientation;
- UINT32 pressure;
-} POINTER_TOUCH_INFO;
-
-/*
- * Macros to retrieve information from pointer input message parameters
- */
-#define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam))
-#define IS_POINTER_FLAG_SET_WPARAM(wParam, flag) (((DWORD)HIWORD(wParam) & (flag)) == (flag))
-#define IS_POINTER_NEW_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_NEW)
-#define IS_POINTER_INRANGE_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_INRANGE)
-#define IS_POINTER_INCONTACT_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_INCONTACT)
-#define IS_POINTER_FIRSTBUTTON_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIRSTBUTTON)
-#define IS_POINTER_SECONDBUTTON_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_SECONDBUTTON)
-#define IS_POINTER_THIRDBUTTON_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_THIRDBUTTON)
-#define IS_POINTER_FOURTHBUTTON_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FOURTHBUTTON)
-#define IS_POINTER_FIFTHBUTTON_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIFTHBUTTON)
-#define IS_POINTER_PRIMARY_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_PRIMARY)
-#define HAS_POINTER_CONFIDENCE_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CONFIDENCE)
-#define IS_POINTER_CANCELED_WPARAM(wParam) \
- IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CANCELED)
-
-typedef BOOL(WINAPI *GHOST_WIN32_GetPointerInfoHistory)(UINT32 pointerId,
- UINT32 *entriesCount,
- POINTER_INFO *pointerInfo);
-typedef BOOL(WINAPI *GHOST_WIN32_GetPointerPenInfoHistory)(UINT32 pointerId,
- UINT32 *entriesCount,
- POINTER_PEN_INFO *penInfo);
-typedef BOOL(WINAPI *GHOST_WIN32_GetPointerTouchInfoHistory)(UINT32 pointerId,
- UINT32 *entriesCount,
- POINTER_TOUCH_INFO *touchInfo);
-
struct GHOST_PointerInfoWin32 {
GHOST_TInt32 pointerId;
GHOST_TInt32 isPrimary;
@@ -576,9 +411,6 @@ class GHOST_WindowWin32 : public GHOST_Window {
/** `user32.dll` handle */
HMODULE m_user32;
- GHOST_WIN32_GetPointerInfoHistory m_fpGetPointerInfoHistory;
- GHOST_WIN32_GetPointerPenInfoHistory m_fpGetPointerPenInfoHistory;
- GHOST_WIN32_GetPointerTouchInfoHistory m_fpGetPointerTouchInfoHistory;
HWND m_parentWindowHwnd;
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 4fcdbfe7c20edfc1204c0aa46c98ea25354abcd
+Subproject 27fe7f3a4f964b53af436c4da4ddea337eff0c7
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 7d78c8a63f2f4b146f9327ddc0d567a5921b94e
+Subproject 5a82baad9f986722104280e8354a4427d8e9eab
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 3969386bad7..dd84dfa2df8 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -153,7 +153,7 @@ class PREFERENCES_OT_copy_prev(Operator):
def execute(self, _context):
import shutil
- shutil.copytree(self._old_path(), self._new_path(), dirs_exist_ok=True)
+ shutil.copytree(self._old_path(), self._new_path(), dirs_exist_ok=True, symlinks=True)
# reload preferences and recent-files.txt
bpy.ops.wm.read_userpref()
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index 29c17711c2a..6ba8750e9df 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -628,7 +628,7 @@ class LightMapPack(Operator):
name="New Image",
description=(
"Assign new images for every mesh (only one if "
- "shared tex space enabled)"
+ "Share Texture Space is enabled)"
),
default=False,
)
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 89ce742b81e..1208ca0a64a 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -660,8 +660,12 @@ class NODE_PT_quality(bpy.types.Panel):
snode = context.space_data
tree = snode.node_tree
+ prefs = bpy.context.preferences
col = layout.column()
+ if prefs.experimental.use_full_frame_compositor:
+ col.prop(tree, "execution_mode")
+
col.prop(tree, "render_quality", text="Render")
col.prop(tree, "edit_quality", text="Edit")
col.prop(tree, "chunk_size")
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index b24b6e84939..e9bfe6cd4e2 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -1398,8 +1398,8 @@ class SEQUENCER_PT_source(SequencerButtonsPanel, Panel):
box.template_image_stereo_3d(strip.stereo_3d_format)
# Resolution.
- col = layout.column(align=True)
- col = col.box()
+ col = layout.box()
+ col = col.column(align=True)
split = col.split(factor=0.5, align=False)
split.alignment = 'RIGHT'
split.label(text="Resolution")
@@ -1409,6 +1409,14 @@ class SEQUENCER_PT_source(SequencerButtonsPanel, Panel):
split.label(text="%dx%d" % size, translate=False)
else:
split.label(text="None")
+ #FPS
+ if elem.orig_fps:
+ split = col.split(factor=0.5, align=False)
+ split.alignment = 'RIGHT'
+ split.label(text="FPS")
+ split.alignment = 'LEFT'
+ split.label(text="%.2f" % elem.orig_fps, translate=False)
+
class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index de78b88c0f6..d85fe16d654 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2256,6 +2256,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
context, (
({"property": "use_new_hair_type"}, "T68981"),
({"property": "use_new_point_cloud_type"}, "T75717"),
+ ({"property": "use_full_frame_compositor"}, "T88150"),
),
)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 4bff18cd1be..05c7ef756c7 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -503,6 +503,7 @@ geometry_node_categories = [
GeometryNodeCategory("GEO_CURVE", "Curve", items=[
NodeItem("GeometryNodeCurveToMesh"),
NodeItem("GeometryNodeCurveResample"),
+ NodeItem("GeometryNodeMeshToCurve"),
]),
GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=[
NodeItem("GeometryNodeBoundBox"),
diff --git a/release/windows/manifest/blender.exe.manifest.in b/release/windows/manifest/blender.exe.manifest.in
index e73ddf3267b..b516efe24cb 100644
--- a/release/windows/manifest/blender.exe.manifest.in
+++ b/release/windows/manifest/blender.exe.manifest.in
@@ -13,12 +13,6 @@
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
- <!-- Windows 8 -->
- <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
- <!-- Windows 7 -->
- <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
- <!-- Windows Vista -->
- <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<dependency>
diff --git a/source/blender/blenfont/intern/blf_font_win32_compat.c b/source/blender/blenfont/intern/blf_font_win32_compat.c
index 7d130204c07..e573d3bd224 100644
--- a/source/blender/blenfont/intern/blf_font_win32_compat.c
+++ b/source/blender/blenfont/intern/blf_font_win32_compat.c
@@ -66,7 +66,7 @@ static unsigned long ft_ansi_stream_io(FT_Stream stream,
file = STREAM_FILE(stream);
if (stream->pos != offset) {
- fseek(file, offset, SEEK_SET);
+ BLI_fseek(file, offset, SEEK_SET);
}
return fread(buffer, 1, count, file);
@@ -93,7 +93,7 @@ static FT_Error FT_Stream_Open__win32_compat(FT_Stream stream, const char *filep
return FT_THROW(Cannot_Open_Resource);
}
- fseek(file, 0, SEEK_END);
+ BLI_fseek(file, 0LL, SEEK_END);
stream->size = ftell(file);
if (!stream->size) {
fprintf(stderr,
@@ -104,7 +104,7 @@ static FT_Error FT_Stream_Open__win32_compat(FT_Stream stream, const char *filep
return FT_THROW(Cannot_Open_Stream);
}
- fseek(file, 0, SEEK_SET);
+ BLI_fseek(file, 0LL, SEEK_SET);
stream->descriptor.pointer = file;
stream->read = ft_ansi_stream_io;
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 0bab980cfcd..eb937ac9608 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 1
+#define BLENDER_FILE_SUBVERSION 2
/* 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_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 7ac45ac4883..e16507bf3cc 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -258,8 +258,10 @@ void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b);
void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_hint);
void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id);
-bool BKE_id_new_name_validate(struct ListBase *lb, struct ID *id, const char *name)
- ATTR_NONNULL(1, 2);
+bool BKE_id_new_name_validate(struct ListBase *lb,
+ struct ID *id,
+ const char *name,
+ const bool do_linked_data) ATTR_NONNULL(1, 2);
void BKE_lib_id_clear_library_data(struct Main *bmain, struct ID *id);
/* Affect whole Main database. */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 448f4ae48ad..fb6647cb68d 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1305,15 +1305,18 @@ void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteSyncFromAdd(bNode *node);
+void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node);
void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len);
+void ntreeCompositCryptomatteLayerPrefix(const Scene *scene,
+ const bNode *node,
+ char *r_prefix,
+ size_t prefix_len);
/* Update the runtime layer names with the cryptomatte layer names of the references
* render layer or image. */
-void ntreeCompositCryptomatteUpdateLayerNames(bNode *node);
-struct CryptomatteSession *ntreeCompositCryptomatteSession(bNode *node);
+void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node);
+struct CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node);
/** \} */
@@ -1426,6 +1429,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_MATERIAL_ASSIGN 1049
#define GEO_NODE_INPUT_MATERIAL 1050
#define GEO_NODE_MATERIAL_REPLACE 1051
+#define GEO_NODE_MESH_TO_CURVE 1052
/** \} */
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index d8fbdf26d93..be827cd338d 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -1423,7 +1423,8 @@ static bool collection_instance_find_recursive(Collection *collection,
}
LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
- if (collection_instance_find_recursive(collection_child->collection, instance_collection)) {
+ if (collection_child->collection != NULL &&
+ collection_instance_find_recursive(collection_child->collection, instance_collection)) {
return true;
}
}
diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c
index 470c2f2d246..4aaecc26eff 100644
--- a/source/blender/blenkernel/intern/customdata_file.c
+++ b/source/blender/blenkernel/intern/customdata_file.c
@@ -167,7 +167,7 @@ static bool cdf_read_header(CDataFile *cdf)
offset += header->structbytes;
header->structbytes = sizeof(CDataFileHeader);
- if (fseek(f, offset, SEEK_SET) != 0) {
+ if (BLI_fseek(f, offset, SEEK_SET) != 0) {
return false;
}
@@ -201,7 +201,7 @@ static bool cdf_read_header(CDataFile *cdf)
mesh->structbytes = sizeof(CDataFileMeshHeader);
}
- if (fseek(f, offset, SEEK_SET) != 0) {
+ if (BLI_fseek(f, offset, SEEK_SET) != 0) {
return false;
}
@@ -233,7 +233,7 @@ static bool cdf_read_header(CDataFile *cdf)
offset += layer->structbytes;
layer->structbytes = sizeof(CDataFileLayer);
- if (fseek(f, offset, SEEK_SET) != 0) {
+ if (BLI_fseek(f, offset, SEEK_SET) != 0) {
return false;
}
}
@@ -321,7 +321,7 @@ bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
offset += cdf->layer[a].datasize;
}
- return (fseek(cdf->readf, offset, SEEK_SET) == 0);
+ return (BLI_fseek(cdf->readf, offset, SEEK_SET) == 0);
}
bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 0fa3bb29ccd..bd76357617a 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -127,9 +127,10 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
}
em->looptris = looptris;
+ em->tottri = looptris_tot;
/* after allocating the em->looptris, we're ready to tessellate */
- BM_mesh_calc_tessellation(em->bm, em->looptris, &em->tottri);
+ BM_mesh_calc_tessellation(em->bm, em->looptris);
}
void BKE_editmesh_looptri_calc(BMEditMesh *em)
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 9abd00c2b4f..69840ba1612 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -544,9 +544,9 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
}
}
-static void join_curve_splines(Span<GeometryInstanceGroup> set_groups, CurveComponent &result)
+static CurveEval *join_curve_splines(Span<GeometryInstanceGroup> set_groups)
{
- CurveEval *new_curve = new CurveEval();
+ Vector<SplinePtr> new_splines;
for (const GeometryInstanceGroup &set_group : set_groups) {
const GeometrySet &set = set_group.geometry_set;
if (!set.has_curve()) {
@@ -558,10 +558,18 @@ static void join_curve_splines(Span<GeometryInstanceGroup> set_groups, CurveComp
for (const float4x4 &transform : set_group.transforms) {
SplinePtr new_spline = source_spline->copy();
new_spline->transform(transform);
- new_curve->add_spline(std::move(new_spline));
+ new_splines.append(std::move(new_spline));
}
}
}
+ if (new_splines.is_empty()) {
+ return nullptr;
+ }
+
+ CurveEval *new_curve = new CurveEval();
+ for (SplinePtr &new_spline : new_splines) {
+ new_curve->add_spline(std::move(new_spline));
+ }
for (SplinePtr &spline : new_curve->splines()) {
/* Spline instances should have no custom attributes, since they always come
@@ -573,8 +581,7 @@ static void join_curve_splines(Span<GeometryInstanceGroup> set_groups, CurveComp
}
new_curve->attributes.reallocate(new_curve->splines().size());
-
- result.replace(new_curve);
+ return new_curve;
}
static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
@@ -639,14 +646,17 @@ static void join_instance_groups_volume(Span<GeometryInstanceGroup> set_groups,
{
/* Not yet supported. Joining volume grids with the same name requires resampling of at least
* one of the grids. The cell size of the resulting volume has to be determined somehow. */
- VolumeComponent &dst_component = result.get_component_for_write<VolumeComponent>();
- UNUSED_VARS(set_groups, dst_component);
+ UNUSED_VARS(set_groups, result);
}
static void join_instance_groups_curve(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
{
+ CurveEval *curve = join_curve_splines(set_groups);
+ if (curve == nullptr) {
+ return;
+ }
CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
- join_curve_splines(set_groups, dst_component);
+ dst_component.replace(curve);
}
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set)
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index f93bf494ee9..490abe05169 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -164,7 +164,7 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id)
id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
id->flag &= ~LIB_INDIRECT_WEAK_LINK;
if (id_in_mainlist) {
- if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL)) {
+ if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL, false)) {
bmain->is_memfile_undo_written = false;
}
}
@@ -833,7 +833,9 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv)
ListBase *lb = which_libbase(bmain, GS(id->name));
BKE_main_lock(bmain);
BLI_addtail(lb, id);
- BKE_id_new_name_validate(lb, id, NULL);
+ /* We need to allow adding extra datablocks into libraries too, e.g. to support generating new
+ * overrides for recursive resync. */
+ BKE_id_new_name_validate(lb, id, NULL, true);
/* alphabetic insertion: is in new_id */
id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT);
bmain->is_memfile_undo_written = false;
@@ -989,7 +991,7 @@ void BKE_main_id_repair_duplicate_names_listbase(ListBase *lb)
}
for (i = 0; i < lb_len; i++) {
if (!BLI_gset_add(gset, id_array[i]->name + 2)) {
- BKE_id_new_name_validate(lb, id_array[i], NULL);
+ BKE_id_new_name_validate(lb, id_array[i], NULL, false);
}
}
BLI_gset_free(gset, NULL);
@@ -1092,7 +1094,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
BKE_main_lock(bmain);
BLI_addtail(lb, id);
- BKE_id_new_name_validate(lb, id, name);
+ BKE_id_new_name_validate(lb, id, name, false);
bmain->is_memfile_undo_written = false;
/* alphabetic insertion: is in new_id */
BKE_main_unlock(bmain);
@@ -1557,7 +1559,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name, ID **r_id_sorting_
* and that current one is not. */
bool is_valid = false;
for (id_test = lb->first; id_test; id_test = id_test->next) {
- if (id != id_test && !ID_IS_LINKED(id_test)) {
+ if (id != id_test && id_test->lib == id->lib) {
if (id_test->name[2] == final_name[0] && STREQ(final_name, id_test->name + 2)) {
/* We expect final_name to not be already used, so this is a failure. */
is_valid = false;
@@ -1613,7 +1615,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name, ID **r_id_sorting_
for (id_test = lb->first; id_test; id_test = id_test->next) {
char base_name_test[MAX_ID_NAME - 2];
int number_test;
- if ((id != id_test) && !ID_IS_LINKED(id_test) && (name[0] == id_test->name[2]) &&
+ if ((id != id_test) && (id_test->lib == id->lib) && (name[0] == id_test->name[2]) &&
(ELEM(id_test->name[base_name_len + 2], '.', '\0')) &&
STREQLEN(name, id_test->name + 2, base_name_len) &&
(BLI_split_name_num(base_name_test, &number_test, id_test->name + 2, '.') ==
@@ -1702,15 +1704,18 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name, ID **r_id_sorting_
*
* Only for local IDs (linked ones already have a unique ID in their library).
*
+ * \param do_linked_data if true, also ensure a unique name in case the given \a id is linked
+ * (otherwise, just ensure that it is properly sorted).
+ *
* \return true if a new name had to be created.
*/
-bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname)
+bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const bool do_linked_data)
{
bool result = false;
char name[MAX_ID_NAME - 2];
- /* If library, don't rename, but do ensure proper sorting. */
- if (ID_IS_LINKED(id)) {
+ /* If library, don't rename (unless explicitely required), but do ensure proper sorting. */
+ if (!do_linked_data && ID_IS_LINKED(id)) {
id_sort_by_name(lb, id, NULL);
return result;
@@ -2193,9 +2198,9 @@ void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
/* search for id */
idtest = BLI_findstring(lb, name + 2, offsetof(ID, name) + 2);
- if (idtest != NULL) {
+ if (idtest != NULL && !ID_IS_LINKED(idtest)) {
/* BKE_id_new_name_validate also takes care of sorting. */
- BKE_id_new_name_validate(lb, idtest, NULL);
+ BKE_id_new_name_validate(lb, idtest, NULL, false);
bmain->is_memfile_undo_written = false;
}
}
@@ -2205,8 +2210,9 @@ void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
*/
void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
{
+ BLI_assert(!ID_IS_LINKED(id));
ListBase *lb = which_libbase(bmain, GS(id->name));
- if (BKE_id_new_name_validate(lb, id, name)) {
+ if (BKE_id_new_name_validate(lb, id, name, false)) {
bmain->is_memfile_undo_written = false;
}
}
diff --git a/source/blender/blenkernel/intern/lib_id_test.cc b/source/blender/blenkernel/intern/lib_id_test.cc
index fbe4a15da1c..8e21ae88aa6 100644
--- a/source/blender/blenkernel/intern/lib_id_test.cc
+++ b/source/blender/blenkernel/intern/lib_id_test.cc
@@ -20,6 +20,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
+#include "BLI_string.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -110,4 +111,63 @@ TEST(lib_id_main_sort, linked_ids_1)
test_lib_id_main_sort_free(&ctx);
}
+TEST(lib_id_main_unique_name, local_ids_1)
+{
+ LibIDMainSortTestContext ctx = {nullptr};
+ test_lib_id_main_sort_init(&ctx);
+ EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
+
+ ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
+ ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
+ ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
+ test_lib_id_main_sort_check_order({id_a, id_b, id_c});
+
+ BLI_strncpy(id_c->name, id_a->name, sizeof(id_c->name));
+ BKE_id_new_name_validate(&ctx.bmain->objects, id_c, NULL, false);
+ EXPECT_TRUE(strcmp(id_c->name + 2, "OB_A.001") == 0);
+ EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
+ EXPECT_TRUE(ctx.bmain->objects.first == id_a);
+ EXPECT_TRUE(ctx.bmain->objects.last == id_b);
+ test_lib_id_main_sort_check_order({id_a, id_c, id_b});
+
+ test_lib_id_main_sort_free(&ctx);
+}
+
+TEST(lib_id_main_unique_name, linked_ids_1)
+{
+ LibIDMainSortTestContext ctx = {nullptr};
+ test_lib_id_main_sort_init(&ctx);
+ EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
+
+ Library *lib_a = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_A"));
+ Library *lib_b = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_B"));
+ ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
+ ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
+ ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
+
+ id_a->lib = lib_a;
+ id_sort_by_name(&ctx.bmain->objects, id_a, nullptr);
+ id_b->lib = lib_a;
+ id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
+ BLI_strncpy(id_b->name, id_a->name, sizeof(id_b->name));
+ BKE_id_new_name_validate(&ctx.bmain->objects, id_b, NULL, true);
+ EXPECT_TRUE(strcmp(id_b->name + 2, "OB_A.001") == 0);
+ EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
+ EXPECT_TRUE(ctx.bmain->objects.first == id_c);
+ EXPECT_TRUE(ctx.bmain->objects.last == id_b);
+ test_lib_id_main_sort_check_order({id_c, id_a, id_b});
+
+ id_b->lib = lib_b;
+ id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
+ BLI_strncpy(id_b->name, id_a->name, sizeof(id_b->name));
+ BKE_id_new_name_validate(&ctx.bmain->objects, id_b, NULL, true);
+ EXPECT_TRUE(strcmp(id_b->name + 2, "OB_A") == 0);
+ EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
+ EXPECT_TRUE(ctx.bmain->objects.first == id_c);
+ EXPECT_TRUE(ctx.bmain->objects.last == id_b);
+ test_lib_id_main_sort_check_order({id_c, id_a, id_b});
+
+ test_lib_id_main_sort_free(&ctx);
+}
+
} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 0e2317c72de..4d5085d6ad5 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -252,6 +252,13 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id)
return false;
}
+ /* A bit weird, but those embedded IDs are handled by their owner ID anyway, so we can just
+ * assume they are never user-edited, actual proper detection will happen from their owner check.
+ */
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ return false;
+ }
+
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
@@ -421,7 +428,8 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
/* If other ID is a linked one, but not from the same library as our reference, then we
* consider we should also remap it, as part of recursive resync. */
- if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != reference_id->lib) {
+ if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != reference_id->lib &&
+ other_id != local_id) {
BKE_libblock_relink_ex(bmain,
other_id,
reference_id,
@@ -461,6 +469,8 @@ typedef struct LibOverrideGroupTagData {
ID *id_root;
uint tag;
uint missing_tag;
+ /* Whether we are looping on override data, or their references (linked) one. */
+ bool is_override;
} LibOverrideGroupTagData;
/* Tag all IDs in dependency relationships within an override hierarchy/group.
@@ -473,6 +483,7 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
{
Main *bmain = data->bmain;
ID *id = data->id_root;
+ const bool is_override = data->is_override;
MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
BLI_assert(entry != NULL);
@@ -494,16 +505,16 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
}
/* We only consider IDs from the same library. */
ID *to_id = *to_id_entry->id_pointer.to;
- if (!ID_IS_LINKED(to_id) && !ID_IS_OVERRIDE_LIBRARY(to_id)) {
- /* Pure local data is a barrier of dependency in override cases. */
+ if (to_id == NULL || to_id->lib != id->lib ||
+ (is_override && !ID_IS_OVERRIDE_LIBRARY(to_id))) {
+ /* IDs from different libraries, or non-override IDs in case we are processing overrides, are
+ * both barriers of dependency. */
continue;
}
- if (to_id != NULL && to_id->lib == id->lib) {
- LibOverrideGroupTagData sub_data = *data;
- sub_data.id_root = to_id;
- if (lib_override_hierarchy_dependencies_recursive_tag(&sub_data)) {
- id->tag |= data->tag;
- }
+ LibOverrideGroupTagData sub_data = *data;
+ sub_data.id_root = to_id;
+ if (lib_override_hierarchy_dependencies_recursive_tag(&sub_data)) {
+ id->tag |= data->tag;
}
}
@@ -515,6 +526,7 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
Main *bmain = data->bmain;
ID *id_owner = data->id_root;
BLI_assert(ID_IS_LINKED(id_owner));
+ BLI_assert(!data->is_override);
const uint tag = data->tag;
const uint missing_tag = data->missing_tag;
@@ -580,6 +592,7 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
{
Main *bmain = data->bmain;
ID *id_root = data->id_root;
+ BLI_assert(!data->is_override);
if ((id_root->tag & LIB_TAG_MISSING)) {
id_root->tag |= data->missing_tag;
@@ -606,11 +619,12 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
}
}
-static void lib_override_local_group_tag_recursive(LibOverrideGroupTagData *data)
+static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *data)
{
Main *bmain = data->bmain;
ID *id_owner = data->id_root;
BLI_assert(ID_IS_OVERRIDE_LIBRARY(id_owner));
+ BLI_assert(data->is_override);
const uint tag = data->tag;
const uint missing_tag = data->missing_tag;
@@ -658,15 +672,16 @@ static void lib_override_local_group_tag_recursive(LibOverrideGroupTagData *data
/* Recursively process the dependencies. */
LibOverrideGroupTagData sub_data = *data;
sub_data.id_root = to_id;
- lib_override_local_group_tag_recursive(&sub_data);
+ lib_override_overrides_group_tag_recursive(&sub_data);
}
}
/* This will tag all override IDs of an override group defined by the given `id_root`. */
-static void lib_override_local_group_tag(LibOverrideGroupTagData *data)
+static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data)
{
ID *id_root = data->id_root;
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
+ BLI_assert(data->is_override);
if ((id_root->override_library->reference->tag & LIB_TAG_MISSING)) {
id_root->tag |= data->missing_tag;
@@ -676,14 +691,17 @@ static void lib_override_local_group_tag(LibOverrideGroupTagData *data)
}
/* Tag all local overrides in id_root's group. */
- lib_override_local_group_tag_recursive(data);
+ lib_override_overrides_group_tag_recursive(data);
}
static bool lib_override_library_create_do(Main *bmain, ID *id_root)
{
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {
- .bmain = bmain, .id_root = id_root, .tag = LIB_TAG_DOIT, .missing_tag = LIB_TAG_MISSING};
+ LibOverrideGroupTagData data = {.bmain = bmain,
+ .id_root = id_root,
+ .tag = LIB_TAG_DOIT,
+ .missing_tag = LIB_TAG_MISSING,
+ .is_override = false};
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -934,12 +952,16 @@ bool BKE_lib_override_library_resync(Main *bmain,
ID *id_root_reference = id_root->override_library->reference;
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {
- .bmain = bmain, .id_root = id_root, .tag = LIB_TAG_DOIT, .missing_tag = LIB_TAG_MISSING};
- lib_override_local_group_tag(&data);
+ LibOverrideGroupTagData data = {.bmain = bmain,
+ .id_root = id_root,
+ .tag = LIB_TAG_DOIT,
+ .missing_tag = LIB_TAG_MISSING,
+ .is_override = true};
+ lib_override_overrides_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
data.id_root = id_root_reference;
+ data.is_override = false;
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -1277,6 +1299,58 @@ bool BKE_lib_override_library_resync(Main *bmain,
return success;
}
+/* Ensures parent collection (or objects) in the same override group are also tagged for resync.
+ *
+ * This is needed since otherwise, some (new) ID added in one sub-collection might be used in
+ * another unrelated sub-collection, if 'root' collection is not resynced separated resync of those
+ * sub-collections would be unaware that this is the same ID, and would re-generate several
+ * overrides for it.
+ *
+ * TODO: This is a sub-optimal, simple solution. At some point, we should rather find a way to
+ * resync a set of 'sub-roots' overrides, instead of having to 'go back' to the real root and
+ * resync the whole hierarchy. */
+static ID *lib_override_library_main_resync_find_root_recurse(ID *id, int *level)
+{
+ (*level)++;
+ ID *return_id = id;
+
+ switch (GS(id->name)) {
+ case ID_GR: {
+ /* Find the highest valid collection in the parenting hierarchy.
+ * Note that in practice, in any decent common case there is only one well defined root
+ * collection anyway. */
+ int max_level = *level;
+ Collection *collection = (Collection *)id;
+ LISTBASE_FOREACH (CollectionParent *, collection_parent_iter, &collection->parents) {
+ Collection *collection_parent = collection_parent_iter->collection;
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(collection_parent) &&
+ collection_parent->id.lib == id->lib) {
+ int tmp_level = *level;
+ ID *tmp_id = lib_override_library_main_resync_find_root_recurse(&collection_parent->id,
+ &tmp_level);
+ if (tmp_level > max_level) {
+ max_level = tmp_level;
+ return_id = tmp_id;
+ }
+ }
+ }
+ break;
+ }
+ case ID_OB: {
+ Object *object = (Object *)id;
+ if (object->parent != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(object->parent) &&
+ object->parent->id.lib == id->lib) {
+ return_id = lib_override_library_main_resync_find_root_recurse(&object->parent->id, level);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return return_id;
+}
+
/* Ensure resync of all overrides at one level of indirect usage.
*
* We need to handle each level independently, since an override at level n may be affected by
@@ -1312,7 +1386,8 @@ static void lib_override_library_main_resync_on_library_indirect_level(
LibOverrideGroupTagData data = {.bmain = bmain,
.id_root = id->override_library->reference,
.tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING};
+ .missing_tag = LIB_TAG_MISSING,
+ .is_override = false};
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data);
@@ -1396,6 +1471,9 @@ static void lib_override_library_main_resync_on_library_indirect_level(
(!ID_IS_LINKED(id) && library_indirect_level != 0)) {
continue;
}
+
+ int level = 0;
+ id = lib_override_library_main_resync_find_root_recurse(id, &level);
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id));
do_continue = true;
@@ -1550,9 +1628,12 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
/* Tag all library overrides in the chains of dependencies from the given root one. */
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {
- .bmain = bmain, .id_root = id_root, .tag = LIB_TAG_DOIT, .missing_tag = LIB_TAG_MISSING};
- lib_override_local_group_tag(&data);
+ LibOverrideGroupTagData data = {.bmain = bmain,
+ .id_root = id_root,
+ .tag = LIB_TAG_DOIT,
+ .missing_tag = LIB_TAG_MISSING,
+ .is_override = true};
+ lib_override_overrides_group_tag(&data);
BKE_main_relations_free(bmain);
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 3377f5c69dc..d0864e85373 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -5066,6 +5066,7 @@ static void registerGeometryNodes()
register_node_type_geo_mesh_primitive_ico_sphere();
register_node_type_geo_mesh_primitive_line();
register_node_type_geo_mesh_primitive_uv_sphere();
+ register_node_type_geo_mesh_to_curve();
register_node_type_geo_object_info();
register_node_type_geo_point_distribute();
register_node_type_geo_point_instance();
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 39f65d76e3c..60c216a8401 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -205,12 +205,11 @@ static int write_audio_frame(FFMpegContext *context)
success = -1;
}
- av_packet_rescale_ts(pkt, c->time_base, context->audio_stream->time_base);
- if (pkt->duration > 0) {
- pkt->duration = av_rescale_q(pkt->duration, c->time_base, context->audio_stream->time_base);
- }
-
pkt->stream_index = context->audio_stream->index;
+ av_packet_rescale_ts(pkt, c->time_base, context->audio_stream->time_base);
+# ifdef FFMPEG_USE_DURATION_WORKAROUND
+ my_guess_pkt_duration(context->outfile, context->audio_stream, pkt);
+# endif
pkt->flags |= AV_PKT_FLAG_KEY;
@@ -349,6 +348,10 @@ static int write_video_frame(FFMpegContext *context, int cfra, AVFrame *frame, R
packet->stream_index = context->video_stream->index;
av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base);
+# ifdef FFMPEG_USE_DURATION_WORKAROUND
+ my_guess_pkt_duration(context->outfile, context->video_stream, packet);
+# endif
+
if (av_interleaved_write_frame(context->outfile, packet) != 0) {
success = -1;
break;
@@ -515,6 +518,48 @@ static void set_ffmpeg_properties(RenderData *rd,
}
}
+static AVRational calc_time_base(uint den, double num, int codec_id)
+{
+ /* Convert the input 'num' to an integer. Simply shift the decimal places until we get an integer
+ * (within a floating point error range).
+ * For example if we have `den = 3` and `num = 0.1` then the fps is: `den/num = 30` fps.
+ * When converting this to a FFMPEG time base, we want num to be an integer.
+ * So we simply move the decimal places of both numbers. i.e. `den = 30`, `num = 1`. */
+ float eps = FLT_EPSILON;
+ const uint DENUM_MAX = (codec_id == AV_CODEC_ID_MPEG4) ? (1UL << 16) - 1 : (1UL << 31) - 1;
+
+ /* Calculate the precision of the initial floating point number. */
+ if (num > 1.0) {
+ const uint num_integer_bits = log2_floor_u((unsigned int)num);
+
+ /* Formula for calculating the epsilon value: (power of two range) / (pow mantissa bits)
+ * For example, a float has 23 mantissa bits and the float value 3.5f as a pow2 range of
+ * (4-2=2):
+ * (2) / pow2(23) = floating point precision for 3.5f
+ */
+ eps = (float)(1 << num_integer_bits) * FLT_EPSILON;
+ }
+
+ /* Calculate how many decimal shifts we can do until we run out of precision. */
+ const int max_num_shift = fabsf(log10f(eps));
+ /* Calculate how many times we can shift the denominator. */
+ const int max_den_shift = log10f(DENUM_MAX) - log10f(den);
+ const int max_iter = min_ii(max_num_shift, max_den_shift);
+
+ for (int i = 0; i < max_iter && fabs(num - round(num)) > eps; i++) {
+ /* Increase the number and denominator until both are integers. */
+ num *= 10;
+ den *= 10;
+ eps *= 10;
+ }
+
+ AVRational time_base;
+ time_base.den = den;
+ time_base.num = (int)num;
+
+ return time_base;
+}
+
/* prepare a video stream for the output file */
static AVStream *alloc_video_stream(FFMpegContext *context,
@@ -545,13 +590,24 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
c->codec_id = codec_id;
c->codec_type = AVMEDIA_TYPE_VIDEO;
+ codec = avcodec_find_encoder(c->codec_id);
+ if (!codec) {
+ fprintf(stderr, "Couldn't find valid video codec\n");
+ avcodec_free_context(&c);
+ context->video_codec = NULL;
+ return NULL;
+ }
+
+ /* Load codec defaults into 'c'. */
+ avcodec_get_context_defaults3(c, codec);
+
/* Get some values from the current render settings */
c->width = rectx;
c->height = recty;
- /* FIXME: Really bad hack (tm) for NTSC support */
if (context->ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
+ /* FIXME: Really bad hack (tm) for NTSC support */
c->time_base.den = 2997;
c->time_base.num = 100;
}
@@ -559,21 +615,23 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
c->time_base.den = rd->frs_sec;
c->time_base.num = (int)rd->frs_sec_base;
}
- else if (compare_ff(rd->frs_sec_base, 1.001f, 0.000001f)) {
- /* This converts xx/1.001 (which is used in presets) to xx000/1001 (which is used in the rest
- * of the world, including FFmpeg). */
- c->time_base.den = (int)(rd->frs_sec * 1000);
- c->time_base.num = (int)(rd->frs_sec_base * 1000);
- }
else {
- /* This calculates a fraction (DENUM_MAX / num) which approximates the scene frame rate
- * (frs_sec / frs_sec_base). It uses the maximum denominator allowed by FFmpeg.
- */
- const double DENUM_MAX = (codec_id == AV_CODEC_ID_MPEG4) ? (1UL << 16) - 1 : (1UL << 31) - 1;
- const double num = (DENUM_MAX / (double)rd->frs_sec) * rd->frs_sec_base;
+ c->time_base = calc_time_base(rd->frs_sec, rd->frs_sec_base, codec_id);
+ }
- c->time_base.den = (int)DENUM_MAX;
- c->time_base.num = (int)num;
+ /* As per the time-base documentation here:
+ * https://www.ffmpeg.org/ffmpeg-codecs.html#Codec-Options
+ * We want to set the time base to (1 / fps) for fixed frame rate video.
+ * If it is not possible, we want to set the time-base numbers to something as
+ * small as possible.
+ */
+ if (c->time_base.num != 1) {
+ AVRational new_time_base;
+ if (av_reduce(
+ &new_time_base.num, &new_time_base.den, c->time_base.num, c->time_base.den, INT_MAX)) {
+ /* Exact reduction was possible. Use the new value. */
+ c->time_base = new_time_base;
+ }
}
st->time_base = c->time_base;
@@ -585,6 +643,11 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
ffmpeg_dict_set_int(&opts, "lossless", 1);
}
else if (context->ffmpeg_crf >= 0) {
+ /* As per https://trac.ffmpeg.org/wiki/Encode/VP9 we must set the bit rate to zero when
+ * encoding with vp9 in crf mode.
+ * Set this to always be zero for other codecs as well.
+ * We don't care about bit rate in crf mode. */
+ c->bit_rate = 0;
ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
}
else {
@@ -624,12 +687,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
}
}
- codec = avcodec_find_encoder(c->codec_id);
- if (!codec) {
- avcodec_free_context(&c);
- return NULL;
- }
-
/* Be sure to use the correct pixel format(e.g. RGB, YUV) */
if (codec->pix_fmts) {
@@ -646,12 +703,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
}
- if (codec_id == AV_CODEC_ID_H264) {
- /* correct wrong default ffmpeg param which crash x264 */
- c->qmin = 10;
- c->qmax = 51;
- }
-
/* Keep lossless encodes in the RGB domain. */
if (codec_id == AV_CODEC_ID_HUFFYUV) {
if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
@@ -711,10 +762,14 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
c->thread_type = FF_THREAD_SLICE;
}
- if (avcodec_open2(c, codec, &opts) < 0) {
+ int ret = avcodec_open2(c, codec, &opts);
+
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't initialize video codec: %s\n", av_err2str(ret));
BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
av_dict_free(&opts);
avcodec_free_context(&c);
+ context->video_codec = NULL;
return NULL;
}
av_dict_free(&opts);
@@ -774,6 +829,17 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
c->codec_id = codec_id;
c->codec_type = AVMEDIA_TYPE_AUDIO;
+ codec = avcodec_find_encoder(c->codec_id);
+ if (!codec) {
+ fprintf(stderr, "Couldn't find valid audio codec\n");
+ avcodec_free_context(&c);
+ context->audio_codec = NULL;
+ return NULL;
+ }
+
+ /* Load codec defaults into 'c'. */
+ avcodec_get_context_defaults3(c, codec);
+
c->sample_rate = rd->ffcodecdata.audio_mixrate;
c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
@@ -803,13 +869,6 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
c->sample_fmt = AV_SAMPLE_FMT_FLT;
}
- codec = avcodec_find_encoder(c->codec_id);
- if (!codec) {
- // XXX error("Couldn't find a valid audio codec");
- avcodec_free_context(&c);
- return NULL;
- }
-
if (codec->sample_fmts) {
/* Check if the preferred sample format for this codec is supported.
* this is because, depending on the version of libav,
@@ -849,11 +908,14 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
set_ffmpeg_properties(rd, c, "audio", &opts);
- if (avcodec_open2(c, codec, &opts) < 0) {
- // XXX error("Couldn't initialize audio codec");
+ int ret = avcodec_open2(c, codec, &opts);
+
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't initialize audio codec: %s\n", av_err2str(ret));
BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
av_dict_free(&opts);
avcodec_free_context(&c);
+ context->audio_codec = NULL;
return NULL;
}
av_dict_free(&opts);
@@ -1181,6 +1243,9 @@ static void flush_ffmpeg(FFMpegContext *context)
packet->stream_index = context->video_stream->index;
av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base);
+# ifdef FFMPEG_USE_DURATION_WORKAROUND
+ my_guess_pkt_duration(context->outfile, context->video_stream, packet);
+# endif
int write_ret = av_interleaved_write_frame(context->outfile, packet);
if (write_ret != 0) {
@@ -1630,49 +1695,7 @@ static void ffmpeg_set_expert_options(RenderData *rd)
IDP_FreePropertyContent(rd->ffcodecdata.properties);
}
- if (codec_id == AV_CODEC_ID_H264) {
- /*
- * All options here are for x264, but must be set via ffmpeg.
- * The names are therefore different - Search for "x264 to FFmpeg option mapping"
- * to get a list.
- */
-
- /*
- * Use CABAC coder. Using "coder:1", which should be equivalent,
- * crashes Blender for some reason. Either way - this is no big deal.
- */
- BKE_ffmpeg_property_add_string(rd, "video", "coder:vlc");
-
- /*
- * The other options were taken from the libx264-default.preset
- * included in the ffmpeg distribution.
- */
-
- /* This breaks compatibility for QT. */
- // BKE_ffmpeg_property_add_string(rd, "video", "flags:loop");
- BKE_ffmpeg_property_add_string(rd, "video", "cmp:chroma");
- BKE_ffmpeg_property_add_string(rd, "video", "partitions:parti4x4"); /* Deprecated. */
- BKE_ffmpeg_property_add_string(rd, "video", "partitions:partp8x8"); /* Deprecated. */
- BKE_ffmpeg_property_add_string(rd, "video", "partitions:partb8x8"); /* Deprecated. */
- BKE_ffmpeg_property_add_string(rd, "video", "me:hex");
- BKE_ffmpeg_property_add_string(rd, "video", "subq:6");
- BKE_ffmpeg_property_add_string(rd, "video", "me_range:16");
- BKE_ffmpeg_property_add_string(rd, "video", "qdiff:4");
- BKE_ffmpeg_property_add_string(rd, "video", "keyint_min:25");
- BKE_ffmpeg_property_add_string(rd, "video", "sc_threshold:40");
- BKE_ffmpeg_property_add_string(rd, "video", "i_qfactor:0.71");
- BKE_ffmpeg_property_add_string(rd, "video", "b_strategy:1");
- BKE_ffmpeg_property_add_string(rd, "video", "bf:3");
- BKE_ffmpeg_property_add_string(rd, "video", "refs:2");
- BKE_ffmpeg_property_add_string(rd, "video", "qcomp:0.6");
-
- BKE_ffmpeg_property_add_string(rd, "video", "trellis:0");
- BKE_ffmpeg_property_add_string(rd, "video", "weightb:1");
- BKE_ffmpeg_property_add_string(rd, "video", "8x8dct:1");
- BKE_ffmpeg_property_add_string(rd, "video", "fast-pskip:1");
- BKE_ffmpeg_property_add_string(rd, "video", "wpredp:2");
- }
- else if (codec_id == AV_CODEC_ID_DNXHD) {
+ if (codec_id == AV_CODEC_ID_DNXHD) {
if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT) {
BKE_ffmpeg_property_add_string(rd, "video", "mbd:rd");
}
diff --git a/source/blender/blenlib/BLI_mpq3.hh b/source/blender/blenlib/BLI_mpq3.hh
index fb5e2b61cdb..b9eda2ad7e1 100644
--- a/source/blender/blenlib/BLI_mpq3.hh
+++ b/source/blender/blenlib/BLI_mpq3.hh
@@ -218,6 +218,15 @@ struct mpq3 {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
+ static mpq_class dot_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
+ {
+ buffer = a;
+ buffer *= b;
+ buffer.x += buffer.y;
+ buffer.x += buffer.z;
+ return buffer.x;
+ }
+
static mpq3 cross(const mpq3 &a, const mpq3 &b)
{
return mpq3(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]);
@@ -246,6 +255,13 @@ struct mpq3 {
return mpq3::dot(diff, diff);
}
+ static mpq_class distance_squared_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
+ {
+ buffer = a;
+ buffer -= b;
+ return mpq3::dot(buffer, buffer);
+ }
+
static mpq3 interpolate(const mpq3 &a, const mpq3 &b, mpq_class t)
{
mpq_class s = 1 - t;
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 106bd5bc793..107c27da6a2 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -171,7 +171,7 @@ size_t BLI_gzip_mem_to_file_at_pos(
z_stream strm;
unsigned char out[CHUNK];
- fseek(file, gz_stream_offset, 0);
+ BLI_fseek(file, gz_stream_offset, 0);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
@@ -217,7 +217,7 @@ size_t BLI_ungzip_file_to_mem_at_pos(void *buf, size_t len, FILE *file, size_t g
size_t chunk = 256 * 1024;
unsigned char in[CHUNK];
- fseek(file, gz_stream_offset, 0);
+ BLI_fseek(file, gz_stream_offset, 0);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index 25291b8c3b0..cc27e9238c3 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -41,6 +41,7 @@
# include "BLI_set.hh"
# include "BLI_span.hh"
# include "BLI_stack.hh"
+# include "BLI_task.hh"
# include "BLI_vector.hh"
# include "BLI_vector_set.hh"
@@ -48,6 +49,10 @@
# include "BLI_mesh_boolean.hh"
+# ifdef WITH_TBB
+# include "tbb/spin_mutex.h"
+# endif
+
// # define PERFDEBUG
namespace blender::meshintersect {
@@ -1690,9 +1695,24 @@ static int find_containing_cell(const Vert *v,
* If the closest point is on an edge, return 0, 1, or 2
* for edges ab, bc, or ca in *r_edge; else -1.
* (Adapted from #closest_on_tri_to_point_v3()).
+ * The arguments ab, ac, ..., r are used as temporaries
+ * in this routine. Passing them in from the caller can
+ * avoid many allocs and frees of temporary mpq3 values
+ * and the mpq_class values within them.
*/
-static mpq_class closest_on_tri_to_point(
- const mpq3 &p, const mpq3 &a, const mpq3 &b, const mpq3 &c, int *r_edge, int *r_vert)
+static mpq_class closest_on_tri_to_point(const mpq3 &p,
+ const mpq3 &a,
+ const mpq3 &b,
+ const mpq3 &c,
+ mpq3 &ab,
+ mpq3 &ac,
+ mpq3 &ap,
+ mpq3 &bp,
+ mpq3 &cp,
+ mpq3 &m,
+ mpq3 &r,
+ int *r_edge,
+ int *r_vert)
{
constexpr int dbg_level = 0;
if (dbg_level > 0) {
@@ -1700,11 +1720,15 @@ static mpq_class closest_on_tri_to_point(
std::cout << " a = " << a << ", b = " << b << ", c = " << c << "\n";
}
/* Check if p in vertex region outside a. */
- mpq3 ab = b - a;
- mpq3 ac = c - a;
- mpq3 ap = p - a;
- mpq_class d1 = mpq3::dot(ab, ap);
- mpq_class d2 = mpq3::dot(ac, ap);
+ ab = b;
+ ab -= a;
+ ac = c;
+ ac -= a;
+ ap = p;
+ ap -= a;
+
+ mpq_class d1 = mpq3::dot_with_buffer(ab, ap, m);
+ mpq_class d2 = mpq3::dot_with_buffer(ac, ap, m);
if (d1 <= 0 && d2 <= 0) {
/* Barycentric coordinates (1,0,0). */
*r_edge = -1;
@@ -1712,12 +1736,13 @@ static mpq_class closest_on_tri_to_point(
if (dbg_level > 0) {
std::cout << " answer = a\n";
}
- return mpq3::distance_squared(p, a);
+ return mpq3::distance_squared_with_buffer(p, a, m);
}
/* Check if p in vertex region outside b. */
- mpq3 bp = p - b;
- mpq_class d3 = mpq3::dot(ab, bp);
- mpq_class d4 = mpq3::dot(ac, bp);
+ bp = p;
+ bp -= b;
+ mpq_class d3 = mpq3::dot_with_buffer(ab, bp, m);
+ mpq_class d4 = mpq3::dot_with_buffer(ac, bp, m);
if (d3 >= 0 && d4 <= d3) {
/* Barycentric coordinates (0,1,0). */
*r_edge = -1;
@@ -1725,25 +1750,28 @@ static mpq_class closest_on_tri_to_point(
if (dbg_level > 0) {
std::cout << " answer = b\n";
}
- return mpq3::distance_squared(p, b);
+ return mpq3::distance_squared_with_buffer(p, b, m);
}
/* Check if p in region of ab. */
mpq_class vc = d1 * d4 - d3 * d2;
if (vc <= 0 && d1 >= 0 && d3 <= 0) {
mpq_class v = d1 / (d1 - d3);
/* Barycentric coordinates (1-v,v,0). */
- mpq3 r = a + v * ab;
+ r = ab;
+ r *= v;
+ r += a;
*r_vert = -1;
*r_edge = 0;
if (dbg_level > 0) {
std::cout << " answer = on ab at " << r << "\n";
}
- return mpq3::distance_squared(p, r);
+ return mpq3::distance_squared_with_buffer(p, r, m);
}
/* Check if p in vertex region outside c. */
- mpq3 cp = p - c;
- mpq_class d5 = mpq3::dot(ab, cp);
- mpq_class d6 = mpq3::dot(ac, cp);
+ cp = p;
+ cp -= c;
+ mpq_class d5 = mpq3::dot_with_buffer(ab, cp, m);
+ mpq_class d6 = mpq3::dot_with_buffer(ac, cp, m);
if (d6 >= 0 && d5 <= d6) {
/* Barycentric coordinates (0,0,1). */
*r_edge = -1;
@@ -1751,49 +1779,54 @@ static mpq_class closest_on_tri_to_point(
if (dbg_level > 0) {
std::cout << " answer = c\n";
}
- return mpq3::distance_squared(p, c);
+ return mpq3::distance_squared_with_buffer(p, c, m);
}
/* Check if p in edge region of ac. */
mpq_class vb = d5 * d2 - d1 * d6;
if (vb <= 0 && d2 >= 0 && d6 <= 0) {
mpq_class w = d2 / (d2 - d6);
/* Barycentric coordinates (1-w,0,w). */
- mpq3 r = a + w * ac;
+ r = ac;
+ r *= w;
+ r += a;
*r_vert = -1;
*r_edge = 2;
if (dbg_level > 0) {
std::cout << " answer = on ac at " << r << "\n";
}
- return mpq3::distance_squared(p, r);
+ return mpq3::distance_squared_with_buffer(p, r, m);
}
/* Check if p in edge region of bc. */
mpq_class va = d3 * d6 - d5 * d4;
if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) {
mpq_class w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
/* Barycentric coordinates (0,1-w,w). */
- mpq3 r = c - b;
- r = w * r;
- r = r + b;
+ r = c;
+ r -= b;
+ r *= w;
+ r += b;
*r_vert = -1;
*r_edge = 1;
if (dbg_level > 0) {
std::cout << " answer = on bc at " << r << "\n";
}
- return mpq3::distance_squared(p, r);
+ return mpq3::distance_squared_with_buffer(p, r, m);
}
/* p inside face region. Compute barycentric coordinates (u,v,w). */
mpq_class denom = 1 / (va + vb + vc);
mpq_class v = vb * denom;
mpq_class w = vc * denom;
- ac = w * ac;
- mpq3 r = a + v * ab;
- r = r + ac;
+ ac *= w;
+ r = ab;
+ r *= v;
+ r += a;
+ r += ac;
*r_vert = -1;
*r_edge = -1;
if (dbg_level > 0) {
std::cout << " answer = inside at " << r << "\n";
}
- return mpq3::distance_squared(p, r);
+ return mpq3::distance_squared_with_buffer(p, r, m);
}
struct ComponentContainer {
@@ -1832,6 +1865,9 @@ static Vector<ComponentContainer> find_component_containers(int comp,
if (dbg_level > 0) {
std::cout << "test vertex in comp: " << test_v << "\n";
}
+
+ mpq3 buf[7];
+
for (int comp_other : components.index_range()) {
if (comp == comp_other) {
continue;
@@ -1856,6 +1892,13 @@ static Vector<ComponentContainer> find_component_containers(int comp,
tri[0]->co_exact,
tri[1]->co_exact,
tri[2]->co_exact,
+ buf[0],
+ buf[1],
+ buf[2],
+ buf[3],
+ buf[4],
+ buf[5],
+ buf[6],
&close_edge,
&close_vert);
if (dbg_level > 1) {
@@ -2567,47 +2610,58 @@ static IMesh raycast_tris_boolean(const IMesh &tm,
BVHTree *tree = raycast_tree(tm);
Vector<Face *> out_faces;
out_faces.reserve(tm.face_size());
- Array<float> in_shape(nshapes, 0);
- Array<int> winding(nshapes, 0);
- for (int t : tm.face_index_range()) {
- Face &tri = *tm.face(t);
- int shape = shape_fn(tri.orig);
- if (dbg_level > 0) {
- std::cout << "process triangle " << t << " = " << &tri << "\n";
- std::cout << "shape = " << shape << "\n";
- }
- test_tri_inside_shapes(tm, shape_fn, nshapes, t, tree, in_shape);
- for (int other_shape = 0; other_shape < nshapes; ++other_shape) {
- if (other_shape == shape) {
- continue;
- }
- /* The in_shape array has a confidence value for "insideness".
- * For most operations, even a hint of being inside
- * gives good results, but when shape is a cutter in a Difference
- * operation, we want to be pretty sure that the point is inside other_shape.
- * E.g., T75827.
- * Also, when the operation is intersection, we also want high confidence.
- */
- bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) ||
- op == BoolOpType::Intersect;
- bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f);
+# ifdef WITH_TBB
+ tbb::spin_mutex mtx;
+# endif
+ const int grainsize = 256;
+ parallel_for(IndexRange(tm.face_size()), grainsize, [&](IndexRange range) {
+ Array<float> in_shape(nshapes, 0);
+ Array<int> winding(nshapes, 0);
+ for (int t : range) {
+ Face &tri = *tm.face(t);
+ int shape = shape_fn(tri.orig);
if (dbg_level > 0) {
- std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape "
- << other_shape << " val = " << in_shape[other_shape] << "\n";
+ std::cout << "process triangle " << t << " = " << &tri << "\n";
+ std::cout << "shape = " << shape << "\n";
}
- winding[other_shape] = inside;
- }
- bool do_flip;
- bool do_remove = raycast_test_remove(op, winding, shape, &do_flip);
- if (!do_remove) {
- if (!do_flip) {
- out_faces.append(&tri);
+ test_tri_inside_shapes(tm, shape_fn, nshapes, t, tree, in_shape);
+ for (int other_shape = 0; other_shape < nshapes; ++other_shape) {
+ if (other_shape == shape) {
+ continue;
+ }
+ /* The in_shape array has a confidence value for "insideness".
+ * For most operations, even a hint of being inside
+ * gives good results, but when shape is a cutter in a Difference
+ * operation, we want to be pretty sure that the point is inside other_shape.
+ * E.g., T75827.
+ * Also, when the operation is intersection, we also want high confidence.
+ */
+ bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) ||
+ op == BoolOpType::Intersect;
+ bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f);
+ if (dbg_level > 0) {
+ std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape "
+ << other_shape << " val = " << in_shape[other_shape] << "\n";
+ }
+ winding[other_shape] = inside;
}
- else {
- raycast_add_flipped(out_faces, tri, arena);
+ bool do_flip;
+ bool do_remove = raycast_test_remove(op, winding, shape, &do_flip);
+ {
+# ifdef WITH_TBB
+ tbb::spin_mutex::scoped_lock lock(mtx);
+# endif
+ if (!do_remove) {
+ if (!do_flip) {
+ out_faces.append(&tri);
+ }
+ else {
+ raycast_add_flipped(out_faces, tri, arena);
+ }
+ }
}
}
- }
+ });
BLI_bvhtree_free(tree);
ans.set_faces(out_faces);
return ans;
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc
index 636209883c3..97f856476c5 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -1165,13 +1165,19 @@ static int filter_plane_side(const double3 &p,
* Assumes ab is not perpendicular to n.
* This works because the ratio of the projections of ab and ac onto n is the same as
* the ratio along the line ab of the intersection point to the whole of ab.
+ * The ab, ac, and dotbuf arguments are used as a temporaries; declaring them
+ * in the caller can avoid many allocs and frees of mpq3 and mpq_class structures.
*/
-static inline mpq3 tti_interp(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &n)
-{
- mpq3 ab = a - b;
- mpq_class den = mpq3::dot(ab, n);
+static inline mpq3 tti_interp(
+ const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &n, mpq3 &ab, mpq3 &ac, mpq3 &dotbuf)
+{
+ ab = a;
+ ab -= b;
+ ac = a;
+ ac -= c;
+ mpq_class den = mpq3::dot_with_buffer(ab, n, dotbuf);
BLI_assert(den != 0);
- mpq_class alpha = mpq3::dot(a - c, n) / den;
+ mpq_class alpha = mpq3::dot_with_buffer(ac, n, dotbuf) / den;
return a - alpha * ab;
}
@@ -1179,11 +1185,28 @@ static inline mpq3 tti_interp(const mpq3 &a, const mpq3 &b, const mpq3 &c, const
* Return +1, 0, -1 as a + ad is above, on, or below the oriented plane containing a, b, c in CCW
* order. This is the same as -oriented(a, b, c, a + ad), but uses fewer arithmetic operations.
* TODO: change arguments to `const Vert *` and use floating filters.
+ * The ba, ca, n, and dotbuf arguments are used as temporaries; declaring them
+ * in the caller can avoid many allocs and frees of mpq3 and mpq_class structures.
*/
-static inline int tti_above(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &ad)
+static inline int tti_above(const mpq3 &a,
+ const mpq3 &b,
+ const mpq3 &c,
+ const mpq3 &ad,
+ mpq3 &ba,
+ mpq3 &ca,
+ mpq3 &n,
+ mpq3 &dotbuf)
{
- mpq3 n = mpq3::cross(b - a, c - a);
- return sgn(mpq3::dot(ad, n));
+ ba = b;
+ ba -= a;
+ ca = c;
+ ca -= a;
+
+ n.x = ba.y * ca.z - ba.z * ca.y;
+ n.y = ba.z * ca.x - ba.x * ca.z;
+ n.z = ba.x * ca.y - ba.y * ca.x;
+
+ return sgn(mpq3::dot_with_buffer(ad, n, dotbuf));
}
/**
@@ -1227,20 +1250,21 @@ static ITT_value itt_canon2(const mpq3 &p1,
mpq3 p1p2 = p2 - p1;
mpq3 intersect_1;
mpq3 intersect_2;
+ mpq3 buf[4];
bool no_overlap = false;
/* Top test in classification tree. */
- if (tti_above(p1, q1, r2, p1p2) > 0) {
+ if (tti_above(p1, q1, r2, p1p2, buf[0], buf[1], buf[2], buf[3]) > 0) {
/* Middle right test in classification tree. */
- if (tti_above(p1, r1, r2, p1p2) <= 0) {
+ if (tti_above(p1, r1, r2, p1p2, buf[0], buf[1], buf[2], buf[3]) <= 0) {
/* Bottom right test in classification tree. */
- if (tti_above(p1, r1, q2, p1p2) > 0) {
+ if (tti_above(p1, r1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) > 0) {
/* Overlap is [k [i l] j]. */
if (dbg_level > 0) {
std::cout << "overlap [k [i l] j]\n";
}
/* i is intersect with p1r1. l is intersect with p2r2. */
- intersect_1 = tti_interp(p1, r1, p2, n2);
- intersect_2 = tti_interp(p2, r2, p1, n1);
+ intersect_1 = tti_interp(p1, r1, p2, n2, buf[0], buf[1], buf[2]);
+ intersect_2 = tti_interp(p2, r2, p1, n1, buf[0], buf[1], buf[2]);
}
else {
/* Overlap is [i [k l] j]. */
@@ -1248,8 +1272,8 @@ static ITT_value itt_canon2(const mpq3 &p1,
std::cout << "overlap [i [k l] j]\n";
}
/* k is intersect with p2q2. l is intersect is p2r2. */
- intersect_1 = tti_interp(p2, q2, p1, n1);
- intersect_2 = tti_interp(p2, r2, p1, n1);
+ intersect_1 = tti_interp(p2, q2, p1, n1, buf[0], buf[1], buf[2]);
+ intersect_2 = tti_interp(p2, r2, p1, n1, buf[0], buf[1], buf[2]);
}
}
else {
@@ -1262,7 +1286,7 @@ static ITT_value itt_canon2(const mpq3 &p1,
}
else {
/* Middle left test in classification tree. */
- if (tti_above(p1, q1, q2, p1p2) < 0) {
+ if (tti_above(p1, q1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) < 0) {
/* No overlap: [i j] [k l]. */
if (dbg_level > 0) {
std::cout << "no overlap: [i j] [k l]\n";
@@ -1271,14 +1295,14 @@ static ITT_value itt_canon2(const mpq3 &p1,
}
else {
/* Bottom left test in classification tree. */
- if (tti_above(p1, r1, q2, p1p2) >= 0) {
+ if (tti_above(p1, r1, q2, p1p2, buf[0], buf[1], buf[2], buf[3]) >= 0) {
/* Overlap is [k [i j] l]. */
if (dbg_level > 0) {
std::cout << "overlap [k [i j] l]\n";
}
/* i is intersect with p1r1. j is intersect with p1q1. */
- intersect_1 = tti_interp(p1, r1, p2, n2);
- intersect_2 = tti_interp(p1, q1, p2, n2);
+ intersect_1 = tti_interp(p1, r1, p2, n2, buf[0], buf[1], buf[2]);
+ intersect_2 = tti_interp(p1, q1, p2, n2, buf[0], buf[1], buf[2]);
}
else {
/* Overlap is [i [k j] l]. */
@@ -1286,8 +1310,8 @@ static ITT_value itt_canon2(const mpq3 &p1,
std::cout << "overlap [i [k j] l]\n";
}
/* k is intersect with p2q2. j is intersect with p1q1. */
- intersect_1 = tti_interp(p2, q2, p1, n1);
- intersect_2 = tti_interp(p1, q1, p2, n2);
+ intersect_1 = tti_interp(p2, q2, p1, n1, buf[0], buf[1], buf[2]);
+ intersect_2 = tti_interp(p1, q1, p2, n2, buf[0], buf[1], buf[2]);
}
}
}
@@ -1438,6 +1462,7 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
return ITT_value(INONE);
}
+ mpq3 buf[2];
const mpq3 &p1 = vp1->co_exact;
const mpq3 &q1 = vq1->co_exact;
const mpq3 &r1 = vr1->co_exact;
@@ -1447,13 +1472,19 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
const mpq3 &n2 = tri2.plane->norm_exact;
if (sp1 == 0) {
- sp1 = sgn(mpq3::dot(p1 - r2, n2));
+ buf[0] = p1;
+ buf[0] -= r2;
+ sp1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
}
if (sq1 == 0) {
- sq1 = sgn(mpq3::dot(q1 - r2, n2));
+ buf[0] = q1;
+ buf[0] -= r2;
+ sq1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
}
if (sr1 == 0) {
- sr1 = sgn(mpq3::dot(r1 - r2, n2));
+ buf[0] = r1;
+ buf[0] -= r2;
+ sr1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
}
if (dbg_level > 1) {
@@ -1473,13 +1504,19 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
/* Repeat for signs of t2's vertices with respect to plane of t1. */
const mpq3 &n1 = tri1.plane->norm_exact;
if (sp2 == 0) {
- sp2 = sgn(mpq3::dot(p2 - r1, n1));
+ buf[0] = p2;
+ buf[0] -= r1;
+ sp2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
}
if (sq2 == 0) {
- sq2 = sgn(mpq3::dot(q2 - r1, n1));
+ buf[0] = q2;
+ buf[0] -= r1;
+ sq2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
}
if (sr2 == 0) {
- sr2 = sgn(mpq3::dot(r2 - r1, n1));
+ buf[0] = r2;
+ buf[0] -= r1;
+ sr2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
}
if (dbg_level > 1) {
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 6338dc95aba..990fc1d65d7 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -446,7 +446,7 @@ static void versions_gpencil_add_main(ListBase *lb, ID *id, const char *name)
id->flag = LIB_FAKEUSER;
*((short *)id->name) = ID_GD;
- BKE_id_new_name_validate(lb, id, name);
+ BKE_id_new_name_validate(lb, id, name, false);
/* alphabetic insertion: is in BKE_id_new_name_validate */
if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) {
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 8c5e86eadd3..c175714c537 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -22,6 +22,7 @@
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
@@ -85,6 +86,32 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
}
}
+static void version_switch_node_input_prefix(Main *bmain)
+{
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_SWITCH) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ /* Skip the "switch" socket. */
+ if (socket == node->inputs.first) {
+ continue;
+ }
+ strcpy(socket->name, socket->name[0] == 'A' ? "False" : "True");
+
+ /* Replace "A" and "B", but keep the unique number suffix at the end. */
+ char number_suffix[8];
+ BLI_strncpy(number_suffix, socket->identifier + 1, sizeof(number_suffix));
+ strcpy(socket->identifier, socket->name);
+ strcat(socket->identifier, number_suffix);
+ }
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -110,6 +137,22 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 2)) {
+ version_switch_node_input_prefix(bmain);
+
+ if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale_xyz[3]")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->pose == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ copy_v3_fl(pchan->custom_scale_xyz, pchan->custom_scale);
+ }
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -121,15 +164,5 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
- if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale_xyz[3]")) {
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->pose == NULL) {
- continue;
- }
- LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
- copy_v3_fl(pchan->custom_scale_xyz, pchan->custom_scale);
- }
- }
- }
}
}
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index c215cf69e3a..af47b9557ef 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -102,6 +102,8 @@ set(SRC
intern/bmesh_mesh_convert.h
intern/bmesh_mesh_duplicate.c
intern/bmesh_mesh_duplicate.h
+ intern/bmesh_mesh_tessellate.c
+ intern/bmesh_mesh_tessellate.h
intern/bmesh_mesh_validate.c
intern/bmesh_mesh_validate.h
intern/bmesh_mods.c
@@ -182,10 +184,6 @@ set(LIB
extern_rangetree
)
-if(MSVC AND NOT MSVC_CLANG)
- string(APPEND CMAKE_C_FLAGS " /WX /wd4101")
-endif()
-
if(WITH_BULLET)
list(APPEND INC_SYS
${BULLET_INCLUDE_DIRS}
@@ -225,6 +223,10 @@ endif()
blender_add_lib(bf_bmesh "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+if(MSVC AND NOT MSVC_CLANG)
+ target_compile_options(bf_bmesh PRIVATE /WX /wd4101)
+endif()
+
if(WITH_GTESTS)
set(TEST_SRC
tests/bmesh_core_test.cc
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 4441ccc0c88..a7e4e011ae2 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -215,6 +215,7 @@ extern "C" {
#include "intern/bmesh_mesh.h"
#include "intern/bmesh_mesh_convert.h"
#include "intern/bmesh_mesh_duplicate.h"
+#include "intern/bmesh_mesh_tessellate.h"
#include "intern/bmesh_mesh_validate.h"
#include "intern/bmesh_mods.h"
#include "intern/bmesh_operators.h"
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
new file mode 100644
index 00000000000..c8ea9429145
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
@@ -0,0 +1,305 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup bmesh
+ *
+ * This file contains code for polygon tessellation
+ * (creating triangles from polygons).
+ */
+
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_alloca.h"
+#include "BLI_heap.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_polyfill_2d.h"
+#include "BLI_polyfill_2d_beautify.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Default Mesh Tessellation
+ * \{ */
+
+static int mesh_calc_tessellation_for_face(BMLoop *(*looptris)[3],
+ BMFace *efa,
+ MemArena **pf_arena_p)
+{
+ switch (efa->len) {
+ case 3: {
+ /* `0 1 2` -> `0 1 2` */
+ BMLoop *l;
+ BMLoop **l_ptr = looptris[0];
+ l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
+ l_ptr[1] = l = l->next;
+ l_ptr[2] = l->next;
+ return 1;
+ }
+ case 4: {
+ /* `0 1 2 3` -> (`0 1 2`, `0 2 3`) */
+ BMLoop *l;
+ BMLoop **l_ptr_a = looptris[0];
+ BMLoop **l_ptr_b = looptris[1];
+ (l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa));
+ (l_ptr_a[1] = l = l->next);
+ (l_ptr_a[2] = l_ptr_b[1] = l = l->next);
+ (l_ptr_b[2] = l->next);
+
+ if (UNLIKELY(is_quad_flip_v3_first_third_fast(
+ l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) {
+ /* Flip out of degenerate 0-2 state. */
+ l_ptr_a[2] = l_ptr_b[2];
+ l_ptr_b[0] = l_ptr_a[1];
+ }
+ return 2;
+ }
+ default: {
+ BMLoop *l_iter, *l_first;
+ BMLoop **l_arr;
+
+ float axis_mat[3][3];
+ float(*projverts)[2];
+ uint(*tris)[3];
+
+ const int tris_len = efa->len - 2;
+
+ MemArena *pf_arena = *pf_arena_p;
+ if (UNLIKELY(pf_arena == NULL)) {
+ pf_arena = *pf_arena_p = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ tris = BLI_memarena_alloc(pf_arena, sizeof(*tris) * tris_len);
+ l_arr = BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len);
+ projverts = BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len);
+
+ axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
+
+ int i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ l_arr[i] = l_iter;
+ mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
+ i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, pf_arena);
+
+ for (i = 0; i < tris_len; i++) {
+ BMLoop **l_ptr = looptris[i];
+ uint *tri = tris[i];
+
+ l_ptr[0] = l_arr[tri[0]];
+ l_ptr[1] = l_arr[tri[1]];
+ l_ptr[2] = l_arr[tri[2]];
+ }
+
+ BLI_memarena_clear(pf_arena);
+ return tris_len;
+ }
+ }
+}
+
+/**
+ * \brief BM_mesh_calc_tessellation get the looptris and its number from a certain bmesh
+ * \param looptris:
+ *
+ * \note \a looptris Must be pre-allocated to at least the size of given by: poly_to_tri_count
+ */
+void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3])
+{
+#ifndef NDEBUG
+ const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+#endif
+
+ BMIter iter;
+ BMFace *efa;
+ int i = 0;
+
+ MemArena *pf_arena = NULL;
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BLI_assert(efa->len >= 3);
+ i += mesh_calc_tessellation_for_face(looptris + i, efa, &pf_arena);
+ }
+
+ if (pf_arena) {
+ BLI_memarena_free(pf_arena);
+ pf_arena = NULL;
+ }
+
+ BLI_assert(i <= looptris_tot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Beauty Mesh Tessellation
+ *
+ * Avoid degenerate triangles.
+ * \{ */
+
+static int mesh_calc_tessellation_for_face_beauty(BMLoop *(*looptris)[3],
+ BMFace *efa,
+ MemArena **pf_arena_p,
+ Heap **pf_heap_p)
+{
+ switch (efa->len) {
+ case 3: {
+ BMLoop *l;
+ BMLoop **l_ptr = looptris[0];
+ l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
+ l_ptr[1] = l = l->next;
+ l_ptr[2] = l->next;
+ return 1;
+ }
+ case 4: {
+ BMLoop *l_v1 = BM_FACE_FIRST_LOOP(efa);
+ BMLoop *l_v2 = l_v1->next;
+ BMLoop *l_v3 = l_v2->next;
+ BMLoop *l_v4 = l_v1->prev;
+
+ /* #BM_verts_calc_rotate_beauty performs excessive checks we don't need!
+ * It's meant for rotating edges, it also calculates a new normal.
+ *
+ * Use #BLI_polyfill_beautify_quad_rotate_calc since we have the normal.
+ */
+#if 0
+ const bool split_13 = (BM_verts_calc_rotate_beauty(
+ l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) < 0.0f);
+#else
+ float axis_mat[3][3], v_quad[4][2];
+ axis_dominant_v3_to_m3(axis_mat, efa->no);
+ mul_v2_m3v3(v_quad[0], axis_mat, l_v1->v->co);
+ mul_v2_m3v3(v_quad[1], axis_mat, l_v2->v->co);
+ mul_v2_m3v3(v_quad[2], axis_mat, l_v3->v->co);
+ mul_v2_m3v3(v_quad[3], axis_mat, l_v4->v->co);
+
+ const bool split_13 = BLI_polyfill_beautify_quad_rotate_calc(
+ v_quad[0], v_quad[1], v_quad[2], v_quad[3]) < 0.0f;
+#endif
+
+ BMLoop **l_ptr_a = looptris[0];
+ BMLoop **l_ptr_b = looptris[1];
+ if (split_13) {
+ l_ptr_a[0] = l_v1;
+ l_ptr_a[1] = l_v2;
+ l_ptr_a[2] = l_v3;
+
+ l_ptr_b[0] = l_v1;
+ l_ptr_b[1] = l_v3;
+ l_ptr_b[2] = l_v4;
+ }
+ else {
+ l_ptr_a[0] = l_v1;
+ l_ptr_a[1] = l_v2;
+ l_ptr_a[2] = l_v4;
+
+ l_ptr_b[0] = l_v2;
+ l_ptr_b[1] = l_v3;
+ l_ptr_b[2] = l_v4;
+ }
+ return 2;
+ }
+ default: {
+ MemArena *pf_arena = *pf_arena_p;
+ Heap *pf_heap = *pf_heap_p;
+ if (UNLIKELY(pf_arena == NULL)) {
+ pf_arena = *pf_arena_p = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ pf_heap = *pf_heap_p = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ }
+
+ BMLoop *l_iter, *l_first;
+ BMLoop **l_arr;
+
+ float axis_mat[3][3];
+ float(*projverts)[2];
+ uint(*tris)[3];
+
+ const int tris_len = efa->len - 2;
+
+ tris = BLI_memarena_alloc(pf_arena, sizeof(*tris) * tris_len);
+ l_arr = BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len);
+ projverts = BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len);
+
+ axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
+
+ int i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ l_arr[i] = l_iter;
+ mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
+ i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, pf_arena);
+
+ BLI_polyfill_beautify(projverts, efa->len, tris, pf_arena, pf_heap);
+
+ for (i = 0; i < tris_len; i++) {
+ BMLoop **l_ptr = looptris[i];
+ uint *tri = tris[i];
+
+ l_ptr[0] = l_arr[tri[0]];
+ l_ptr[1] = l_arr[tri[1]];
+ l_ptr[2] = l_arr[tri[2]];
+ }
+
+ BLI_memarena_clear(pf_arena);
+
+ return tris_len;
+ }
+ }
+}
+
+/**
+ * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
+ */
+void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3])
+{
+#ifndef NDEBUG
+ const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+#endif
+
+ BMIter iter;
+ BMFace *efa;
+ int i = 0;
+
+ MemArena *pf_arena = NULL;
+
+ /* use_beauty */
+ Heap *pf_heap = NULL;
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BLI_assert(efa->len >= 3);
+ i += mesh_calc_tessellation_for_face_beauty(looptris + i, efa, &pf_arena, &pf_heap);
+ }
+
+ if (pf_arena) {
+ BLI_memarena_free(pf_arena);
+
+ BLI_heap_free(pf_heap, NULL);
+ }
+
+ BLI_assert(i <= looptris_tot);
+}
+
+/** \} */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
new file mode 100644
index 00000000000..5606a5a7e02
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
@@ -0,0 +1,24 @@
+/*
+ * 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
+
+/** \file
+ * \ingroup bmesh
+ */
+
+void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]);
+void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3]);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 4ae2cc67140..5397098a7f3 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -18,8 +18,7 @@
* \ingroup bmesh
*
* This file contains code for dealing
- * with polygons (normal/area calculation,
- * tessellation, etc)
+ * with polygons (normal/area calculation, tessellation, etc)
*/
#include "DNA_listBase.h"
@@ -1523,289 +1522,3 @@ void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4])
l = l->next;
r_loops[3] = l;
}
-
-/**
- * \brief BM_mesh_calc_tessellation get the looptris and its number from a certain bmesh
- * \param looptris:
- *
- * \note \a looptris Must be pre-allocated to at least the size of given by: poly_to_tri_count
- */
-void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot)
-{
- /* use this to avoid locking pthread for _every_ polygon
- * and calling the fill function */
-#define USE_TESSFACE_SPEEDUP
-
- /* this assumes all faces can be scan-filled, which isn't always true,
- * worst case we over alloc a little which is acceptable */
-#ifndef NDEBUG
- const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
-#endif
-
- BMIter iter;
- BMFace *efa;
- int i = 0;
-
- MemArena *arena = NULL;
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- /* don't consider two-edged faces */
- if (UNLIKELY(efa->len < 3)) {
- /* do nothing */
- }
-
-#ifdef USE_TESSFACE_SPEEDUP
-
- /* no need to ensure the loop order, we know its ok */
-
- else if (efa->len == 3) {
-# if 0
- int j;
- BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, j) {
- looptris[i][j] = l;
- }
- i += 1;
-# else
- /* more cryptic but faster */
- BMLoop *l;
- BMLoop **l_ptr = looptris[i++];
- l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
- l_ptr[1] = l = l->next;
- l_ptr[2] = l->next;
-# endif
- }
- else if (efa->len == 4) {
-# if 0
- BMLoop *ltmp[4];
- int j;
- BLI_array_grow_items(looptris, 2);
- BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, j) {
- ltmp[j] = l;
- }
-
- looptris[i][0] = ltmp[0];
- looptris[i][1] = ltmp[1];
- looptris[i][2] = ltmp[2];
- i += 1;
-
- looptris[i][0] = ltmp[0];
- looptris[i][1] = ltmp[2];
- looptris[i][2] = ltmp[3];
- i += 1;
-# else
- /* more cryptic but faster */
- BMLoop *l;
- BMLoop **l_ptr_a = looptris[i++];
- BMLoop **l_ptr_b = looptris[i++];
- (l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa));
- (l_ptr_a[1] = l = l->next);
- (l_ptr_a[2] = l_ptr_b[1] = l = l->next);
- (l_ptr_b[2] = l->next);
-# endif
-
- if (UNLIKELY(is_quad_flip_v3_first_third_fast(
- l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) {
- /* flip out of degenerate 0-2 state. */
- l_ptr_a[2] = l_ptr_b[2];
- l_ptr_b[0] = l_ptr_a[1];
- }
- }
-
-#endif /* USE_TESSFACE_SPEEDUP */
-
- else {
- int j;
-
- BMLoop *l_iter;
- BMLoop *l_first;
- BMLoop **l_arr;
-
- float axis_mat[3][3];
- float(*projverts)[2];
- uint(*tris)[3];
-
- const int totfilltri = efa->len - 2;
-
- if (UNLIKELY(arena == NULL)) {
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
-
- tris = BLI_memarena_alloc(arena, sizeof(*tris) * totfilltri);
- l_arr = BLI_memarena_alloc(arena, sizeof(*l_arr) * efa->len);
- projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * efa->len);
-
- axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
-
- j = 0;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- l_arr[j] = l_iter;
- mul_v2_m3v3(projverts[j], axis_mat, l_iter->v->co);
- j++;
- } while ((l_iter = l_iter->next) != l_first);
-
- BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, arena);
-
- for (j = 0; j < totfilltri; j++) {
- BMLoop **l_ptr = looptris[i++];
- uint *tri = tris[j];
-
- l_ptr[0] = l_arr[tri[0]];
- l_ptr[1] = l_arr[tri[1]];
- l_ptr[2] = l_arr[tri[2]];
- }
-
- BLI_memarena_clear(arena);
- }
- }
-
- if (arena) {
- BLI_memarena_free(arena);
- arena = NULL;
- }
-
- *r_looptris_tot = i;
-
- BLI_assert(i <= looptris_tot);
-
-#undef USE_TESSFACE_SPEEDUP
-}
-
-/**
- * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
- */
-void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot)
-{
- /* this assumes all faces can be scan-filled, which isn't always true,
- * worst case we over alloc a little which is acceptable */
-#ifndef NDEBUG
- const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
-#endif
-
- BMIter iter;
- BMFace *efa;
- int i = 0;
-
- MemArena *pf_arena = NULL;
-
- /* use_beauty */
- Heap *pf_heap = NULL;
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- /* don't consider two-edged faces */
- if (UNLIKELY(efa->len < 3)) {
- /* do nothing */
- }
- else if (efa->len == 3) {
- BMLoop *l;
- BMLoop **l_ptr = looptris[i++];
- l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
- l_ptr[1] = l = l->next;
- l_ptr[2] = l->next;
- }
- else if (efa->len == 4) {
- BMLoop *l_v1 = BM_FACE_FIRST_LOOP(efa);
- BMLoop *l_v2 = l_v1->next;
- BMLoop *l_v3 = l_v2->next;
- BMLoop *l_v4 = l_v1->prev;
-
- /* #BM_verts_calc_rotate_beauty performs excessive checks we don't need!
- * It's meant for rotating edges, it also calculates a new normal.
- *
- * Use #BLI_polyfill_beautify_quad_rotate_calc since we have the normal.
- */
-#if 0
- const bool split_13 = (BM_verts_calc_rotate_beauty(
- l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) < 0.0f);
-#else
- float axis_mat[3][3], v_quad[4][2];
- axis_dominant_v3_to_m3(axis_mat, efa->no);
- mul_v2_m3v3(v_quad[0], axis_mat, l_v1->v->co);
- mul_v2_m3v3(v_quad[1], axis_mat, l_v2->v->co);
- mul_v2_m3v3(v_quad[2], axis_mat, l_v3->v->co);
- mul_v2_m3v3(v_quad[3], axis_mat, l_v4->v->co);
-
- const bool split_13 = BLI_polyfill_beautify_quad_rotate_calc(
- v_quad[0], v_quad[1], v_quad[2], v_quad[3]) < 0.0f;
-#endif
-
- BMLoop **l_ptr_a = looptris[i++];
- BMLoop **l_ptr_b = looptris[i++];
- if (split_13) {
- l_ptr_a[0] = l_v1;
- l_ptr_a[1] = l_v2;
- l_ptr_a[2] = l_v3;
-
- l_ptr_b[0] = l_v1;
- l_ptr_b[1] = l_v3;
- l_ptr_b[2] = l_v4;
- }
- else {
- l_ptr_a[0] = l_v1;
- l_ptr_a[1] = l_v2;
- l_ptr_a[2] = l_v4;
-
- l_ptr_b[0] = l_v2;
- l_ptr_b[1] = l_v3;
- l_ptr_b[2] = l_v4;
- }
- }
- else {
- int j;
-
- BMLoop *l_iter;
- BMLoop *l_first;
- BMLoop **l_arr;
-
- float axis_mat[3][3];
- float(*projverts)[2];
- unsigned int(*tris)[3];
-
- const int totfilltri = efa->len - 2;
-
- if (UNLIKELY(pf_arena == NULL)) {
- pf_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
- }
-
- tris = BLI_memarena_alloc(pf_arena, sizeof(*tris) * totfilltri);
- l_arr = BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len);
- projverts = BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len);
-
- axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
-
- j = 0;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- l_arr[j] = l_iter;
- mul_v2_m3v3(projverts[j], axis_mat, l_iter->v->co);
- j++;
- } while ((l_iter = l_iter->next) != l_first);
-
- BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, pf_arena);
-
- BLI_polyfill_beautify(projverts, efa->len, tris, pf_arena, pf_heap);
-
- for (j = 0; j < totfilltri; j++) {
- BMLoop **l_ptr = looptris[i++];
- unsigned int *tri = tris[j];
-
- l_ptr[0] = l_arr[tri[0]];
- l_ptr[1] = l_arr[tri[1]];
- l_ptr[2] = l_arr[tri[2]];
- }
-
- BLI_memarena_clear(pf_arena);
- }
- }
-
- if (pf_arena) {
- BLI_memarena_free(pf_arena);
-
- BLI_heap_free(pf_heap, NULL);
- }
-
- *r_looptris_tot = i;
-
- BLI_assert(i <= looptris_tot);
-}
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 8c2b9ee0bff..e7d5cb2f89d 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -24,9 +24,6 @@ struct Heap;
#include "BLI_compiler_attrs.h"
-void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
-void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
-
void BM_face_calc_tessellation(const BMFace *f,
const bool use_fixed_quad,
BMLoop **r_loops,
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 65391794c12..ac59d832013 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -49,6 +49,8 @@ set(SRC
COM_compositor.h
COM_defines.h
+ intern/COM_BufferOperation.cc
+ intern/COM_BufferOperation.h
intern/COM_CPUDevice.cc
intern/COM_CPUDevice.h
intern/COM_ChunkOrder.cc
@@ -66,14 +68,20 @@ set(SRC
intern/COM_Enums.cc
intern/COM_ExecutionGroup.cc
intern/COM_ExecutionGroup.h
+ intern/COM_ExecutionModel.cc
+ intern/COM_ExecutionModel.h
intern/COM_ExecutionSystem.cc
intern/COM_ExecutionSystem.h
+ intern/COM_FullFrameExecutionModel.cc
+ intern/COM_FullFrameExecutionModel.h
intern/COM_MemoryBuffer.cc
intern/COM_MemoryBuffer.h
intern/COM_MemoryProxy.cc
intern/COM_MemoryProxy.h
intern/COM_MetaData.cc
intern/COM_MetaData.h
+ intern/COM_MultiThreadedOperation.cc
+ intern/COM_MultiThreadedOperation.h
intern/COM_Node.cc
intern/COM_Node.h
intern/COM_NodeConverter.cc
@@ -86,8 +94,12 @@ set(SRC
intern/COM_NodeOperationBuilder.h
intern/COM_OpenCLDevice.cc
intern/COM_OpenCLDevice.h
+ intern/COM_SharedOperationBuffers.cc
+ intern/COM_SharedOperationBuffers.h
intern/COM_SingleThreadedOperation.cc
intern/COM_SingleThreadedOperation.h
+ intern/COM_TiledExecutionModel.cc
+ intern/COM_TiledExecutionModel.h
intern/COM_WorkPackage.cc
intern/COM_WorkPackage.h
intern/COM_WorkScheduler.cc
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index ef889807030..5a52d216117 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -20,6 +20,16 @@
namespace blender::compositor {
+enum class eExecutionModel {
+ /**
+ * Operations are executed from outputs to inputs grouped in execution groups and rendered
+ * in tiles.
+ */
+ Tiled,
+ /** Operations are fully rendered in order from inputs to outputs. */
+ FullFrame
+};
+
/**
* \brief possible data types for sockets
* \ingroup Model
diff --git a/source/blender/compositor/intern/COM_BufferOperation.cc b/source/blender/compositor/intern/COM_BufferOperation.cc
new file mode 100644
index 00000000000..8464d01801f
--- /dev/null
+++ b/source/blender/compositor/intern/COM_BufferOperation.cc
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_BufferOperation.h"
+
+namespace blender::compositor {
+
+BufferOperation::BufferOperation(MemoryBuffer *buffer, DataType data_type)
+{
+ buffer_ = buffer;
+ /* TODO: Implement a MemoryBuffer get_size() method returning a Size2d type. Shorten following
+ * code to: set_resolution(buffer.get_size()) */
+ unsigned int resolution[2];
+ resolution[0] = buffer->getWidth();
+ resolution[1] = buffer->getHeight();
+ setResolution(resolution);
+ addOutputSocket(data_type);
+}
+
+void *BufferOperation::initializeTileData(rcti * /*rect*/)
+{
+ return buffer_;
+}
+
+void BufferOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+{
+ switch (sampler) {
+ case PixelSampler::Nearest:
+ buffer_->read(output, x, y);
+ break;
+ case PixelSampler::Bilinear:
+ default:
+ buffer_->readBilinear(output, x, y);
+ break;
+ case PixelSampler::Bicubic:
+ /* No bicubic. Same implementation as ReadBufferOperation. */
+ buffer_->readBilinear(output, x, y);
+ break;
+ }
+}
+
+void BufferOperation::executePixelFiltered(
+ float output[4], float x, float y, float dx[2], float dy[2])
+{
+ const float uv[2] = {x, y};
+ const float deriv[2][2] = {{dx[0], dx[1]}, {dy[0], dy[1]}};
+ buffer_->readEWA(output, uv, deriv);
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_BufferOperation.h b/source/blender/compositor/intern/COM_BufferOperation.h
new file mode 100644
index 00000000000..f87cd4db94e
--- /dev/null
+++ b/source/blender/compositor/intern/COM_BufferOperation.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_NodeOperation.h"
+
+namespace blender::compositor {
+
+class BufferOperation : public NodeOperation {
+ private:
+ MemoryBuffer *buffer_;
+
+ public:
+ BufferOperation(MemoryBuffer *buffer, DataType data_type);
+
+ void *initializeTileData(rcti *rect) override;
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
+ void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2]) override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_CPUDevice.cc b/source/blender/compositor/intern/COM_CPUDevice.cc
index 29a82bec636..2ca5557e278 100644
--- a/source/blender/compositor/intern/COM_CPUDevice.cc
+++ b/source/blender/compositor/intern/COM_CPUDevice.cc
@@ -30,11 +30,24 @@ CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id)
void CPUDevice::execute(WorkPackage *work_package)
{
- const unsigned int chunkNumber = work_package->chunk_number;
- ExecutionGroup *executionGroup = work_package->execution_group;
-
- executionGroup->getOutputOperation()->executeRegion(&work_package->rect, chunkNumber);
- executionGroup->finalizeChunkExecution(chunkNumber, nullptr);
+ switch (work_package->type) {
+ case eWorkPackageType::Tile: {
+ const unsigned int chunkNumber = work_package->chunk_number;
+ ExecutionGroup *executionGroup = work_package->execution_group;
+
+ executionGroup->getOutputOperation()->executeRegion(&work_package->rect, chunkNumber);
+ executionGroup->finalizeChunkExecution(chunkNumber, nullptr);
+ break;
+ }
+ case eWorkPackageType::CustomFunction: {
+ work_package->execute_fn();
+ break;
+ }
+ }
+
+ if (work_package->executed_fn) {
+ work_package->executed_fn();
+ }
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_CompositorContext.cc b/source/blender/compositor/intern/COM_CompositorContext.cc
index f70f3a8ebfc..61e299c045e 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.cc
+++ b/source/blender/compositor/intern/COM_CompositorContext.cc
@@ -21,6 +21,7 @@
#include <cstdio>
#include "BLI_assert.h"
+#include "DNA_userdef_types.h"
namespace blender::compositor {
@@ -33,6 +34,7 @@ CompositorContext::CompositorContext()
this->m_fastCalculation = false;
this->m_viewSettings = nullptr;
this->m_displaySettings = nullptr;
+ this->m_bnodetree = nullptr;
}
int CompositorContext::getFramenumber() const
@@ -41,4 +43,20 @@ int CompositorContext::getFramenumber() const
return m_rd->cfra;
}
+eExecutionModel CompositorContext::get_execution_model() const
+{
+ if (U.experimental.use_full_frame_compositor) {
+ BLI_assert(m_bnodetree != nullptr);
+ switch (m_bnodetree->execution_mode) {
+ case 1:
+ return eExecutionModel::FullFrame;
+ case 0:
+ return eExecutionModel::Tiled;
+ default:
+ BLI_assert(!"Invalid execution mode");
+ }
+ }
+ return eExecutionModel::Tiled;
+}
+
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h
index e6164246bdd..56251511576 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.h
+++ b/source/blender/compositor/intern/COM_CompositorContext.h
@@ -281,6 +281,11 @@ class CompositorContext {
{
return m_rd->size * 0.01f;
}
+
+ /**
+ * Get active execution model.
+ */
+ eExecutionModel get_execution_model() const;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index dfb4f53fee5..4cf7e09a7d8 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -211,12 +211,14 @@ int DebugInfo::graphviz_legend_group(
return len;
}
-int DebugInfo::graphviz_legend(char *str, int maxlen)
+int DebugInfo::graphviz_legend(char *str, int maxlen, const bool has_execution_groups)
{
int len = 0;
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{\r\n");
- len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "rank = sink;\r\n");
+ if (has_execution_groups) {
+ len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "rank = sink;\r\n");
+ }
len += snprintf(
str + len, maxlen > len ? maxlen - len : 0, "Legend [shape=none, margin=0, label=<\r\n");
@@ -236,21 +238,24 @@ int DebugInfo::graphviz_legend(char *str, int maxlen)
"Viewer", "lightskyblue3", str + len, maxlen > len ? maxlen - len : 0);
len += graphviz_legend_color(
"Active Viewer", "lightskyblue1", str + len, maxlen > len ? maxlen - len : 0);
- len += graphviz_legend_color(
- "Write Buffer", "darkorange", str + len, maxlen > len ? maxlen - len : 0);
- len += graphviz_legend_color(
- "Read Buffer", "darkolivegreen3", str + len, maxlen > len ? maxlen - len : 0);
+ if (has_execution_groups) {
+ len += graphviz_legend_color(
+ "Write Buffer", "darkorange", str + len, maxlen > len ? maxlen - len : 0);
+ len += graphviz_legend_color(
+ "Read Buffer", "darkolivegreen3", str + len, maxlen > len ? maxlen - len : 0);
+ }
len += graphviz_legend_color(
"Input Value", "khaki1", str + len, maxlen > len ? maxlen - len : 0);
- len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<TR><TD></TD></TR>\r\n");
-
- len += graphviz_legend_group(
- "Group Waiting", "white", "dashed", str + len, maxlen > len ? maxlen - len : 0);
- len += graphviz_legend_group(
- "Group Running", "firebrick1", "solid", str + len, maxlen > len ? maxlen - len : 0);
- len += graphviz_legend_group(
- "Group Finished", "chartreuse4", "solid", str + len, maxlen > len ? maxlen - len : 0);
+ if (has_execution_groups) {
+ len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<TR><TD></TD></TR>\r\n");
+ len += graphviz_legend_group(
+ "Group Waiting", "white", "dashed", str + len, maxlen > len ? maxlen - len : 0);
+ len += graphviz_legend_group(
+ "Group Running", "firebrick1", "solid", str + len, maxlen > len ? maxlen - len : 0);
+ len += graphviz_legend_group(
+ "Group Finished", "chartreuse4", "solid", str + len, maxlen > len ? maxlen - len : 0);
+ }
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "</TABLE>\r\n");
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, ">];\r\n");
@@ -387,7 +392,9 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
}
}
- len += graphviz_legend(str + len, maxlen > len ? maxlen - len : 0);
+ const bool has_execution_groups = system->getContext().get_execution_model() ==
+ eExecutionModel::Tiled;
+ len += graphviz_legend(str + len, maxlen > len ? maxlen - len : 0, has_execution_groups);
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n");
diff --git a/source/blender/compositor/intern/COM_Debug.h b/source/blender/compositor/intern/COM_Debug.h
index e1aea69e481..0de3a5e39dc 100644
--- a/source/blender/compositor/intern/COM_Debug.h
+++ b/source/blender/compositor/intern/COM_Debug.h
@@ -129,7 +129,7 @@ class DebugInfo {
const char *name, const char *color, const char *style, char *str, int maxlen);
static int graphviz_legend_group(
const char *name, const char *color, const char *style, char *str, int maxlen);
- static int graphviz_legend(char *str, int maxlen);
+ static int graphviz_legend(char *str, int maxlen, bool has_execution_groups);
static bool graphviz_system(const ExecutionSystem *system, char *str, int maxlen);
};
diff --git a/source/blender/compositor/intern/COM_Enums.h b/source/blender/compositor/intern/COM_Enums.h
index f65ce3e856e..519e7df940e 100644
--- a/source/blender/compositor/intern/COM_Enums.h
+++ b/source/blender/compositor/intern/COM_Enums.h
@@ -70,6 +70,21 @@ enum class eWorkPackageState {
Executed = 2,
};
+/**
+ * \brief Work type to execute.
+ * \ingroup Execution
+ */
+enum class eWorkPackageType {
+ /**
+ * \brief Executes an execution group tile.
+ */
+ Tile = 0,
+ /**
+ * \brief Executes a custom function.
+ */
+ CustomFunction = 1
+};
+
std::ostream &operator<<(std::ostream &os, const eCompositorPriority &priority);
std::ostream &operator<<(std::ostream &os, const eWorkPackageState &execution_state);
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cc b/source/blender/compositor/intern/COM_ExecutionGroup.cc
index 80d453bf7f9..68bda8c70d6 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cc
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc
@@ -157,6 +157,7 @@ void ExecutionGroup::init_work_packages()
if (this->m_chunks_len != 0) {
m_work_packages.resize(this->m_chunks_len);
for (unsigned int index = 0; index < m_chunks_len; index++) {
+ m_work_packages[index].type = eWorkPackageType::Tile;
m_work_packages[index].state = eWorkPackageState::NotScheduled;
m_work_packages[index].execution_group = this;
m_work_packages[index].chunk_number = index;
diff --git a/source/blender/compositor/intern/COM_ExecutionModel.cc b/source/blender/compositor/intern/COM_ExecutionModel.cc
new file mode 100644
index 00000000000..4d7f62e091b
--- /dev/null
+++ b/source/blender/compositor/intern/COM_ExecutionModel.cc
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_ExecutionModel.h"
+
+namespace blender::compositor {
+
+ExecutionModel::ExecutionModel(CompositorContext &context, Span<NodeOperation *> operations)
+ : context_(context), operations_(operations)
+{
+ const bNodeTree *node_tree = context_.getbNodeTree();
+
+ const rctf *viewer_border = &node_tree->viewer_border;
+ border_.use_viewer_border = (node_tree->flag & NTREE_VIEWER_BORDER) &&
+ viewer_border->xmin < viewer_border->xmax &&
+ viewer_border->ymin < viewer_border->ymax;
+ border_.viewer_border = viewer_border;
+
+ const RenderData *rd = context_.getRenderData();
+ /* Case when cropping to render border happens is handled in
+ * compositor output and render layer nodes. */
+ border_.use_render_border = context.isRendering() && (rd->mode & R_BORDER) &&
+ !(rd->mode & R_CROP);
+ border_.render_border = &rd->border;
+}
+
+bool ExecutionModel::is_breaked() const
+{
+ const bNodeTree *btree = context_.getbNodeTree();
+ return btree->test_break(btree->tbh);
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_ExecutionModel.h b/source/blender/compositor/intern/COM_ExecutionModel.h
new file mode 100644
index 00000000000..9e8466b9282
--- /dev/null
+++ b/source/blender/compositor/intern/COM_ExecutionModel.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "BLI_rect.h"
+#include "BLI_vector.hh"
+
+#include "COM_ExecutionSystem.h"
+
+#include <functional>
+
+#ifdef WITH_CXX_GUARDEDALLOC
+# include "MEM_guardedalloc.h"
+#endif
+
+namespace blender::compositor {
+
+class NodeOperation;
+
+/**
+ * Base class for execution models. Contains shared implementation.
+ */
+class ExecutionModel {
+ protected:
+ /**
+ * Render and viewer border info. Coordinates are normalized.
+ */
+ struct {
+ bool use_render_border;
+ const rctf *render_border;
+ bool use_viewer_border;
+ const rctf *viewer_border;
+ } border_;
+
+ /**
+ * Context used during execution.
+ */
+ CompositorContext &context_;
+
+ /**
+ * All operations being executed.
+ */
+ Span<NodeOperation *> operations_;
+
+ public:
+ ExecutionModel(CompositorContext &context, Span<NodeOperation *> operations);
+
+ virtual ~ExecutionModel()
+ {
+ }
+
+ virtual void execute(ExecutionSystem &exec_system) = 0;
+
+ virtual void execute_work(const rcti &UNUSED(work_rect),
+ std::function<void(const rcti &split_rect)> UNUSED(work_func))
+ {
+ BLI_assert(!"Method not supported by current execution model");
+ }
+
+ protected:
+ bool is_breaked() const;
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("COM:BaseExecutionModel")
+#endif
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index e22dc17837b..a12ec774032 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cc
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -21,16 +21,11 @@
#include "BLI_utildefines.h"
#include "PIL_time.h"
-#include "BKE_node.h"
-
-#include "BLT_translation.h"
-
-#include "COM_Converter.h"
#include "COM_Debug.h"
-#include "COM_ExecutionGroup.h"
+#include "COM_FullFrameExecutionModel.h"
#include "COM_NodeOperation.h"
#include "COM_NodeOperationBuilder.h"
-#include "COM_ReadBufferOperation.h"
+#include "COM_TiledExecutionModel.h"
#include "COM_WorkScheduler.h"
#ifdef WITH_CXX_GUARDEDALLOC
@@ -73,41 +68,23 @@ ExecutionSystem::ExecutionSystem(RenderData *rd,
builder.convertToOperations(this);
}
- unsigned int resolution[2];
-
- rctf *viewer_border = &editingtree->viewer_border;
- bool use_viewer_border = (editingtree->flag & NTREE_VIEWER_BORDER) &&
- viewer_border->xmin < viewer_border->xmax &&
- viewer_border->ymin < viewer_border->ymax;
-
- editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Determining resolution"));
-
- for (ExecutionGroup *executionGroup : m_groups) {
- resolution[0] = 0;
- resolution[1] = 0;
- executionGroup->determineResolution(resolution);
-
- if (rendering) {
- /* case when cropping to render border happens is handled in
- * compositor output and render layer nodes
- */
- if ((rd->mode & R_BORDER) && !(rd->mode & R_CROP)) {
- executionGroup->setRenderBorder(
- rd->border.xmin, rd->border.xmax, rd->border.ymin, rd->border.ymax);
- }
- }
-
- if (use_viewer_border) {
- executionGroup->setViewerBorder(
- viewer_border->xmin, viewer_border->xmax, viewer_border->ymin, viewer_border->ymax);
- }
+ switch (m_context.get_execution_model()) {
+ case eExecutionModel::Tiled:
+ execution_model_ = new TiledExecutionModel(m_context, m_operations, m_groups);
+ break;
+ case eExecutionModel::FullFrame:
+ execution_model_ = new FullFrameExecutionModel(m_context, active_buffers_, m_operations);
+ break;
+ default:
+ BLI_assert(!"Non implemented execution model");
+ break;
}
-
- // DebugInfo::graphviz(this);
}
ExecutionSystem::~ExecutionSystem()
{
+ delete execution_model_;
+
for (NodeOperation *operation : m_operations) {
delete operation;
}
@@ -126,100 +103,16 @@ void ExecutionSystem::set_operations(const Vector<NodeOperation *> &operations,
m_groups = groups;
}
-static void update_read_buffer_offset(Vector<NodeOperation *> &operations)
-{
- unsigned int order = 0;
- for (NodeOperation *operation : operations) {
- if (operation->get_flags().is_read_buffer_operation) {
- ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
- readOperation->setOffset(order);
- order++;
- }
- }
-}
-
-static void init_write_operations_for_execution(Vector<NodeOperation *> &operations,
- const bNodeTree *bTree)
-{
- for (NodeOperation *operation : operations) {
- if (operation->get_flags().is_write_buffer_operation) {
- operation->setbNodeTree(bTree);
- operation->initExecution();
- }
- }
-}
-
-static void link_write_buffers(Vector<NodeOperation *> &operations)
-{
- for (NodeOperation *operation : operations) {
- if (operation->get_flags().is_read_buffer_operation) {
- ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation);
- readOperation->updateMemoryBuffer();
- }
- }
-}
-
-static void init_non_write_operations_for_execution(Vector<NodeOperation *> &operations,
- const bNodeTree *bTree)
-{
- for (NodeOperation *operation : operations) {
- if (!operation->get_flags().is_write_buffer_operation) {
- operation->setbNodeTree(bTree);
- operation->initExecution();
- }
- }
-}
-
-static void init_execution_groups_for_execution(Vector<ExecutionGroup *> &groups,
- const int chunk_size)
-{
- for (ExecutionGroup *execution_group : groups) {
- execution_group->setChunksize(chunk_size);
- execution_group->initExecution();
- }
-}
-
void ExecutionSystem::execute()
{
- const bNodeTree *editingtree = this->m_context.getbNodeTree();
- editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Initializing execution"));
-
DebugInfo::execute_started(this);
- update_read_buffer_offset(m_operations);
-
- init_write_operations_for_execution(m_operations, m_context.getbNodeTree());
- link_write_buffers(m_operations);
- init_non_write_operations_for_execution(m_operations, m_context.getbNodeTree());
- init_execution_groups_for_execution(m_groups, m_context.getChunksize());
-
- WorkScheduler::start(this->m_context);
- execute_groups(eCompositorPriority::High);
- if (!this->getContext().isFastCalculation()) {
- execute_groups(eCompositorPriority::Medium);
- execute_groups(eCompositorPriority::Low);
- }
- WorkScheduler::finish();
- WorkScheduler::stop();
-
- editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | De-initializing execution"));
-
- for (NodeOperation *operation : m_operations) {
- operation->deinitExecution();
- }
-
- for (ExecutionGroup *execution_group : m_groups) {
- execution_group->deinitExecution();
- }
+ execution_model_->execute(*this);
}
-void ExecutionSystem::execute_groups(eCompositorPriority priority)
+void ExecutionSystem::execute_work(const rcti &work_rect,
+ std::function<void(const rcti &split_rect)> work_func)
{
- for (ExecutionGroup *execution_group : m_groups) {
- if (execution_group->get_flags().is_output &&
- execution_group->getRenderPriority() == priority) {
- execution_group->execute(this);
- }
- }
+ execution_model_->execute_work(work_rect, work_func);
}
} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index e6170c48778..e106209651c 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -25,6 +25,7 @@ class ExecutionGroup;
#include "COM_ExecutionGroup.h"
#include "COM_Node.h"
#include "COM_NodeOperation.h"
+#include "COM_SharedOperationBuffers.h"
#include "DNA_color_types.h"
#include "DNA_node_types.h"
@@ -115,13 +116,21 @@ namespace blender::compositor {
* \see ExecutionGroup class representing the ExecutionGroup
*/
+/* Forward declarations. */
+class ExecutionModel;
+
/**
* \brief the ExecutionSystem contains the whole compositor tree.
*/
class ExecutionSystem {
-
private:
/**
+ * Contains operations active buffers data. Buffers will be disposed once reader operations are
+ * finished.
+ */
+ SharedOperationBuffers active_buffers_;
+
+ /**
* \brief the context used during execution
*/
CompositorContext m_context;
@@ -136,6 +145,11 @@ class ExecutionSystem {
*/
Vector<ExecutionGroup *> m_groups;
+ /**
+ * Active execution model implementation.
+ */
+ ExecutionModel *execution_model_;
+
private: // methods
public:
/**
@@ -178,9 +192,14 @@ class ExecutionSystem {
return this->m_context;
}
- private:
- void execute_groups(eCompositorPriority priority);
+ SharedOperationBuffers &get_active_buffers()
+ {
+ return active_buffers_;
+ }
+
+ void execute_work(const rcti &work_rect, std::function<void(const rcti &split_rect)> work_func);
+ private:
/* allow the DebugInfo class to look at internals */
friend class DebugInfo;
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
new file mode 100644
index 00000000000..396aa2fcf6f
--- /dev/null
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_FullFrameExecutionModel.h"
+#include "COM_Debug.h"
+#include "COM_ExecutionGroup.h"
+#include "COM_ReadBufferOperation.h"
+#include "COM_WorkScheduler.h"
+
+#include "BLT_translation.h"
+
+#ifdef WITH_CXX_GUARDEDALLOC
+# include "MEM_guardedalloc.h"
+#endif
+
+namespace blender::compositor {
+
+FullFrameExecutionModel::FullFrameExecutionModel(CompositorContext &context,
+ SharedOperationBuffers &shared_buffers,
+ Span<NodeOperation *> operations)
+ : ExecutionModel(context, operations),
+ active_buffers_(shared_buffers),
+ num_operations_finished_(0),
+ work_mutex_(),
+ work_finished_cond_()
+{
+ priorities_.append(eCompositorPriority::High);
+ if (!context.isFastCalculation()) {
+ priorities_.append(eCompositorPriority::Medium);
+ priorities_.append(eCompositorPriority::Low);
+ }
+
+ BLI_mutex_init(&work_mutex_);
+ BLI_condition_init(&work_finished_cond_);
+}
+
+FullFrameExecutionModel::~FullFrameExecutionModel()
+{
+ BLI_condition_end(&work_finished_cond_);
+ BLI_mutex_end(&work_mutex_);
+}
+
+void FullFrameExecutionModel::execute(ExecutionSystem &exec_system)
+{
+ const bNodeTree *node_tree = this->context_.getbNodeTree();
+ node_tree->stats_draw(node_tree->sdh, TIP_("Compositing | Initializing execution"));
+
+ DebugInfo::graphviz(&exec_system);
+
+ determine_areas_to_render_and_reads();
+ render_operations(exec_system);
+}
+
+void FullFrameExecutionModel::determine_areas_to_render_and_reads()
+{
+ const bool is_rendering = context_.isRendering();
+ const bNodeTree *node_tree = context_.getbNodeTree();
+
+ rcti area;
+ for (eCompositorPriority priority : priorities_) {
+ for (NodeOperation *op : operations_) {
+ op->setbNodeTree(node_tree);
+ if (op->isOutputOperation(is_rendering) && op->getRenderPriority() == priority) {
+ get_output_render_area(op, area);
+ determine_areas_to_render(op, area);
+ determine_reads(op);
+ }
+ }
+ }
+}
+
+void FullFrameExecutionModel::ensure_inputs_rendered(NodeOperation *op,
+ ExecutionSystem &exec_system)
+{
+ const int num_inputs = op->getNumberOfInputSockets();
+ for (int i = 0; i < num_inputs; i++) {
+ NodeOperation *input_op = op->get_input_operation(i);
+ if (!active_buffers_.is_operation_rendered(input_op)) {
+ render_operation(input_op, exec_system);
+ }
+ }
+}
+
+Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation *op)
+{
+ const int num_inputs = op->getNumberOfInputSockets();
+ Vector<MemoryBuffer *> inputs_buffers(num_inputs);
+ for (int i = 0; i < num_inputs; i++) {
+ NodeOperation *input_op = op->get_input_operation(i);
+ inputs_buffers[i] = active_buffers_.get_rendered_buffer(input_op);
+ }
+ return inputs_buffers;
+}
+
+MemoryBuffer *FullFrameExecutionModel::create_operation_buffer(NodeOperation *op)
+{
+ rcti op_rect;
+ BLI_rcti_init(&op_rect, 0, op->getWidth(), 0, op->getHeight());
+
+ const DataType data_type = op->getOutputSocket(0)->getDataType();
+ /* TODO: We should check if the operation is constant instead of is_set_operation. Finding a way
+ * to know if an operation is constant has to be implemented yet. */
+ const bool is_a_single_elem = op->get_flags().is_set_operation;
+ return new MemoryBuffer(data_type, op_rect, is_a_single_elem);
+}
+
+void FullFrameExecutionModel::render_operation(NodeOperation *op, ExecutionSystem &exec_system)
+{
+ if (active_buffers_.is_operation_rendered(op)) {
+ return;
+ }
+
+ ensure_inputs_rendered(op, exec_system);
+ Vector<MemoryBuffer *> input_bufs = get_input_buffers(op);
+
+ const bool has_outputs = op->getNumberOfOutputSockets() > 0;
+ MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op) : nullptr;
+ Span<rcti> areas = active_buffers_.get_areas_to_render(op);
+ op->render(op_buf, areas, input_bufs, exec_system);
+ active_buffers_.set_rendered_buffer(op, std::unique_ptr<MemoryBuffer>(op_buf));
+
+ operation_finished(op);
+}
+
+/**
+ * Render output operations in order of priority.
+ */
+void FullFrameExecutionModel::render_operations(ExecutionSystem &exec_system)
+{
+ const bool is_rendering = context_.isRendering();
+
+ WorkScheduler::start(this->context_);
+ for (eCompositorPriority priority : priorities_) {
+ for (NodeOperation *op : operations_) {
+ if (op->isOutputOperation(is_rendering) && op->getRenderPriority() == priority) {
+ render_operation(op, exec_system);
+ }
+ }
+ }
+ WorkScheduler::stop();
+}
+
+/**
+ * Determines all input operations areas needed to render given operation area.
+ * \param operation: Renderer operation.
+ * \param render_area: Area within given operation bounds to render.
+ */
+void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *operation,
+ const rcti &render_area)
+{
+ if (active_buffers_.is_area_registered(operation, render_area)) {
+ return;
+ }
+
+ active_buffers_.register_area(operation, render_area);
+
+ const int num_inputs = operation->getNumberOfInputSockets();
+ for (int i = 0; i < num_inputs; i++) {
+ NodeOperation *input_op = operation->get_input_operation(i);
+ rcti input_op_rect, input_area;
+ BLI_rcti_init(&input_op_rect, 0, input_op->getWidth(), 0, input_op->getHeight());
+ operation->get_area_of_interest(input_op, render_area, input_area);
+
+ /* Ensure area of interest is within operation bounds, cropping areas outside. */
+ BLI_rcti_isect(&input_area, &input_op_rect, &input_area);
+
+ determine_areas_to_render(input_op, input_area);
+ }
+}
+
+/**
+ * Determines the reads given operation and its inputs will receive (i.e: Number of dependent
+ * operations each operation has).
+ */
+void FullFrameExecutionModel::determine_reads(NodeOperation *operation)
+{
+ if (active_buffers_.has_registered_reads(operation)) {
+ return;
+ }
+
+ const int num_inputs = operation->getNumberOfInputSockets();
+ for (int i = 0; i < num_inputs; i++) {
+ NodeOperation *input_op = operation->get_input_operation(i);
+ determine_reads(input_op);
+ active_buffers_.register_read(input_op);
+ }
+}
+
+/**
+ * Calculates given output operation area to be rendered taking into account viewer and render
+ * borders.
+ */
+void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, rcti &r_area)
+{
+ BLI_assert(output_op->isOutputOperation(context_.isRendering()));
+
+ /* By default return operation bounds (no border). */
+ const int op_width = output_op->getWidth();
+ const int op_height = output_op->getHeight();
+ BLI_rcti_init(&r_area, 0, op_width, 0, op_height);
+
+ const bool has_viewer_border = border_.use_viewer_border &&
+ (output_op->get_flags().is_viewer_operation ||
+ output_op->get_flags().is_preview_operation);
+ const bool has_render_border = border_.use_render_border;
+ if (has_viewer_border || has_render_border) {
+ /* Get border with normalized coordinates. */
+ const rctf *norm_border = has_viewer_border ? border_.viewer_border : border_.render_border;
+
+ /* Return de-normalized border. */
+ BLI_rcti_init(&r_area,
+ norm_border->xmin * op_width,
+ norm_border->xmax * op_width,
+ norm_border->ymin * op_height,
+ norm_border->ymax * op_height);
+ }
+}
+
+/**
+ * Multi-threadedly execute given work function passing work_rect splits as argument.
+ */
+void FullFrameExecutionModel::execute_work(const rcti &work_rect,
+ std::function<void(const rcti &split_rect)> work_func)
+{
+ if (is_breaked()) {
+ return;
+ }
+
+ /* Split work vertically to maximize continuous memory. */
+ const int work_height = BLI_rcti_size_y(&work_rect);
+ const int num_sub_works = MIN2(WorkScheduler::get_num_cpu_threads(), work_height);
+ const int split_height = num_sub_works == 0 ? 0 : work_height / num_sub_works;
+ int remaining_height = work_height - split_height * num_sub_works;
+
+ Vector<WorkPackage> sub_works(num_sub_works);
+ int sub_work_y = work_rect.ymin;
+ int num_sub_works_finished = 0;
+ for (int i = 0; i < num_sub_works; i++) {
+ int sub_work_height = split_height;
+
+ /* Distribute remaining height between sub-works. */
+ if (remaining_height > 0) {
+ sub_work_height++;
+ remaining_height--;
+ }
+
+ WorkPackage &sub_work = sub_works[i];
+ sub_work.type = eWorkPackageType::CustomFunction;
+ sub_work.execute_fn = [=, &work_func, &work_rect]() {
+ if (is_breaked()) {
+ return;
+ }
+ rcti split_rect;
+ BLI_rcti_init(
+ &split_rect, work_rect.xmin, work_rect.xmax, sub_work_y, sub_work_y + sub_work_height);
+ work_func(split_rect);
+ };
+ sub_work.executed_fn = [&]() {
+ BLI_mutex_lock(&work_mutex_);
+ num_sub_works_finished++;
+ if (num_sub_works_finished == num_sub_works) {
+ BLI_condition_notify_one(&work_finished_cond_);
+ }
+ BLI_mutex_unlock(&work_mutex_);
+ };
+ WorkScheduler::schedule(&sub_work);
+ sub_work_y += sub_work_height;
+ }
+ BLI_assert(sub_work_y == work_rect.ymax);
+
+ WorkScheduler::finish();
+
+ /* Ensure all sub-works finished.
+ * TODO: This a workaround for WorkScheduler::finish() not waiting all works on queue threading
+ * model. Sync code should be removed once it's fixed. */
+ BLI_mutex_lock(&work_mutex_);
+ if (num_sub_works_finished < num_sub_works) {
+ BLI_condition_wait(&work_finished_cond_, &work_mutex_);
+ }
+ BLI_mutex_unlock(&work_mutex_);
+}
+
+void FullFrameExecutionModel::operation_finished(NodeOperation *operation)
+{
+ /* Report inputs reads so that buffers may be freed/reused. */
+ const int num_inputs = operation->getNumberOfInputSockets();
+ for (int i = 0; i < num_inputs; i++) {
+ active_buffers_.read_finished(operation->get_input_operation(i));
+ }
+
+ num_operations_finished_++;
+ update_progress_bar();
+}
+
+void FullFrameExecutionModel::update_progress_bar()
+{
+ const bNodeTree *tree = context_.getbNodeTree();
+ if (tree) {
+ const float progress = num_operations_finished_ / static_cast<float>(operations_.size());
+ tree->progress(tree->prh, progress);
+
+ char buf[128];
+ BLI_snprintf(buf,
+ sizeof(buf),
+ TIP_("Compositing | Operation %i-%li"),
+ num_operations_finished_ + 1,
+ operations_.size());
+ tree->stats_draw(tree->sdh, buf);
+ }
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
new file mode 100644
index 00000000000..2c0d5e0460a
--- /dev/null
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_ExecutionModel.h"
+
+#ifdef WITH_CXX_GUARDEDALLOC
+# include "MEM_guardedalloc.h"
+#endif
+
+namespace blender::compositor {
+
+/* Forward declarations. */
+class ExecutionGroup;
+
+/**
+ * Fully renders operations in order from inputs to outputs.
+ */
+class FullFrameExecutionModel : public ExecutionModel {
+ private:
+ /**
+ * Contains operations active buffers data. Buffers will be disposed once reader operations are
+ * finished.
+ */
+ SharedOperationBuffers &active_buffers_;
+
+ /**
+ * Number of operations finished.
+ */
+ int num_operations_finished_;
+
+ /**
+ * Order of priorities for output operations execution.
+ */
+ Vector<eCompositorPriority> priorities_;
+
+ ThreadMutex work_mutex_;
+ ThreadCondition work_finished_cond_;
+
+ public:
+ FullFrameExecutionModel(CompositorContext &context,
+ SharedOperationBuffers &shared_buffers,
+ Span<NodeOperation *> operations);
+ ~FullFrameExecutionModel();
+
+ void execute(ExecutionSystem &exec_system) override;
+
+ void execute_work(const rcti &work_rect,
+ std::function<void(const rcti &split_rect)> work_func) override;
+
+ private:
+ void determine_areas_to_render_and_reads();
+ void render_operations(ExecutionSystem &exec_system);
+
+ void ensure_inputs_rendered(NodeOperation *op, ExecutionSystem &exec_system);
+ Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op);
+ MemoryBuffer *create_operation_buffer(NodeOperation *op);
+ void render_operation(NodeOperation *op, ExecutionSystem &exec_system);
+
+ void operation_finished(NodeOperation *operation);
+
+ void get_output_render_area(NodeOperation *output_op, rcti &r_area);
+ void determine_areas_to_render(NodeOperation *operation, const rcti &render_area);
+ void determine_reads(NodeOperation *operation);
+
+ void update_progress_bar();
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("COM:FullFrameExecutionModel")
+#endif
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_MultiThreadedOperation.cc b/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
new file mode 100644
index 00000000000..c54c2edccb0
--- /dev/null
+++ b/source/blender/compositor/intern/COM_MultiThreadedOperation.cc
@@ -0,0 +1,26 @@
+#include "COM_MultiThreadedOperation.h"
+#include "COM_ExecutionSystem.h"
+
+namespace blender::compositor {
+
+MultiThreadedOperation::MultiThreadedOperation()
+{
+ m_num_passes = 1;
+ flags.is_fullframe_operation = true;
+}
+
+void MultiThreadedOperation::update_memory_buffer(MemoryBuffer *output,
+ const rcti &output_area,
+ blender::Span<MemoryBuffer *> inputs,
+ ExecutionSystem &exec_system)
+{
+ for (int current_pass = 0; current_pass < m_num_passes; current_pass++) {
+ update_memory_buffer_started(output, output_area, inputs, exec_system, current_pass);
+ exec_system.execute_work(output_area, [=, &exec_system](const rcti &split_rect) {
+ update_memory_buffer_partial(output, split_rect, inputs, exec_system, current_pass);
+ });
+ update_memory_buffer_finished(output, output_area, inputs, exec_system, current_pass);
+ }
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_MultiThreadedOperation.h b/source/blender/compositor/intern/COM_MultiThreadedOperation.h
new file mode 100644
index 00000000000..97c5fba4ead
--- /dev/null
+++ b/source/blender/compositor/intern/COM_MultiThreadedOperation.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_NodeOperation.h"
+
+namespace blender::compositor {
+
+class MultiThreadedOperation : public NodeOperation {
+ protected:
+ /**
+ * Number of execution passes.
+ */
+ int m_num_passes;
+
+ protected:
+ MultiThreadedOperation();
+
+ /**
+ * Called before an update memory buffer pass is executed. Single-threaded calls.
+ */
+ virtual void update_memory_buffer_started(MemoryBuffer *UNUSED(output),
+ const rcti &UNUSED(output_rect),
+ blender::Span<MemoryBuffer *> UNUSED(inputs),
+ ExecutionSystem &UNUSED(exec_system),
+ int UNUSED(current_pass))
+ {
+ }
+
+ /**
+ * Executes operation updating output memory buffer on output_rect area. Multi-threaded calls.
+ */
+ virtual void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &output_rect,
+ blender::Span<MemoryBuffer *> inputs,
+ ExecutionSystem &exec_system,
+ int current_pass) = 0;
+
+ /**
+ * Called after an update memory buffer pass is executed. Single-threaded calls.
+ */
+ virtual void update_memory_buffer_finished(MemoryBuffer *UNUSED(output),
+ const rcti &UNUSED(output_rect),
+ blender::Span<MemoryBuffer *> UNUSED(inputs),
+ ExecutionSystem &UNUSED(exec_system),
+ int UNUSED(current_pass))
+ {
+ }
+
+ private:
+ void update_memory_buffer(MemoryBuffer *output,
+ const rcti &output_area,
+ blender::Span<MemoryBuffer *> inputs,
+ ExecutionSystem &exec_system) override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc
index be3ea59efa5..83de8a751c4 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cc
+++ b/source/blender/compositor/intern/COM_NodeOperation.cc
@@ -17,8 +17,10 @@
*/
#include <cstdio>
+#include <memory>
#include <typeinfo>
+#include "COM_BufferOperation.h"
#include "COM_ExecutionSystem.h"
#include "COM_ReadBufferOperation.h"
#include "COM_defines.h"
@@ -175,6 +177,177 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
return !first;
}
+/* -------------------------------------------------------------------- */
+/** \name Full Frame Methods
+ * \{ */
+
+/**
+ * \brief Get input operation area being read by this operation on rendering given output area.
+ *
+ * Implementation don't need to ensure r_input_area is within input operation bounds. The
+ * caller must clamp it.
+ * TODO: See if it's possible to use parameter overloading (input_id for example).
+ *
+ * \param input_op_idx: Input operation index for which we want to calculate the area being read.
+ * \param output_area: Area being rendered by this operation.
+ * \param r_input_area: Returned input operation area that needs to be read in order to render
+ * given output area.
+ */
+void NodeOperation::get_area_of_interest(const int input_op_idx,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ if (get_flags().is_fullframe_operation) {
+ r_input_area = output_area;
+ }
+ else {
+ /* Non full-frame operations never implement this method. To ensure correctness assume
+ * whole area is used. */
+ NodeOperation *input_op = getInputOperation(input_op_idx);
+ BLI_rcti_init(&r_input_area, 0, input_op->getWidth(), 0, input_op->getHeight());
+ }
+}
+
+void NodeOperation::get_area_of_interest(NodeOperation *input_op,
+ const rcti &output_area,
+ rcti &r_input_area)
+{
+ for (int i = 0; i < getNumberOfInputSockets(); i++) {
+ if (input_op == getInputOperation(i)) {
+ get_area_of_interest(i, output_area, r_input_area);
+ return;
+ }
+ }
+ BLI_assert(!"input_op is not an input operation.");
+}
+
+/**
+ * Executes operation image manipulation algorithm rendering given areas.
+ * \param output_buf: Buffer to write result to.
+ * \param areas: Areas within this operation bounds to render.
+ * \param inputs_bufs: Inputs operations buffers.
+ * \param exec_system: Execution system.
+ */
+void NodeOperation::render(MemoryBuffer *output_buf,
+ Span<rcti> areas,
+ Span<MemoryBuffer *> inputs_bufs,
+ ExecutionSystem &exec_system)
+{
+ if (get_flags().is_fullframe_operation) {
+ render_full_frame(output_buf, areas, inputs_bufs, exec_system);
+ }
+ else {
+ render_full_frame_fallback(output_buf, areas, inputs_bufs, exec_system);
+ }
+}
+
+/**
+ * Renders given areas using operations full frame implementation.
+ */
+void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
+ Span<rcti> areas,
+ Span<MemoryBuffer *> inputs_bufs,
+ ExecutionSystem &exec_system)
+{
+ initExecution();
+ for (const rcti &area : areas) {
+ update_memory_buffer(output_buf, area, inputs_bufs, exec_system);
+ }
+ deinitExecution();
+}
+
+/**
+ * Renders given areas using operations tiled implementation.
+ */
+void NodeOperation::render_full_frame_fallback(MemoryBuffer *output_buf,
+ Span<rcti> areas,
+ Span<MemoryBuffer *> inputs_bufs,
+ ExecutionSystem &exec_system)
+{
+ Vector<NodeOperationOutput *> orig_input_links = replace_inputs_with_buffers(inputs_bufs);
+
+ initExecution();
+ const bool is_output_operation = getNumberOfOutputSockets() == 0;
+ if (!is_output_operation && output_buf->is_a_single_elem()) {
+ float *output_elem = output_buf->get_elem(0, 0);
+ readSampled(output_elem, 0, 0, PixelSampler::Nearest);
+ }
+ else {
+ for (const rcti &rect : areas) {
+ exec_system.execute_work(rect, [=](const rcti &split_rect) {
+ rcti tile_rect = split_rect;
+ if (is_output_operation) {
+ executeRegion(&tile_rect, 0);
+ }
+ else {
+ render_tile(output_buf, &tile_rect);
+ }
+ });
+ }
+ }
+ deinitExecution();
+
+ remove_buffers_and_restore_original_inputs(orig_input_links);
+}
+
+void NodeOperation::render_tile(MemoryBuffer *output_buf, rcti *tile_rect)
+{
+ const bool is_complex = get_flags().complex;
+ void *tile_data = is_complex ? initializeTileData(tile_rect) : nullptr;
+ const int elem_stride = output_buf->elem_stride;
+ for (int y = tile_rect->ymin; y < tile_rect->ymax; y++) {
+ float *output_elem = output_buf->get_elem(tile_rect->xmin, y);
+ if (is_complex) {
+ for (int x = tile_rect->xmin; x < tile_rect->xmax; x++) {
+ read(output_elem, x, y, tile_data);
+ output_elem += elem_stride;
+ }
+ }
+ else {
+ for (int x = tile_rect->xmin; x < tile_rect->xmax; x++) {
+ readSampled(output_elem, x, y, PixelSampler::Nearest);
+ output_elem += elem_stride;
+ }
+ }
+ }
+ if (tile_data) {
+ deinitializeTileData(tile_rect, tile_data);
+ }
+}
+
+/**
+ * \return Replaced inputs links.
+ */
+Vector<NodeOperationOutput *> NodeOperation::replace_inputs_with_buffers(
+ Span<MemoryBuffer *> inputs_bufs)
+{
+ BLI_assert(inputs_bufs.size() == getNumberOfInputSockets());
+ Vector<NodeOperationOutput *> orig_links(inputs_bufs.size());
+ for (int i = 0; i < inputs_bufs.size(); i++) {
+ NodeOperationInput *input_socket = getInputSocket(i);
+ BufferOperation *buffer_op = new BufferOperation(inputs_bufs[i], input_socket->getDataType());
+ orig_links[i] = input_socket->getLink();
+ input_socket->setLink(buffer_op->getOutputSocket());
+ }
+ return orig_links;
+}
+
+void NodeOperation::remove_buffers_and_restore_original_inputs(
+ Span<NodeOperationOutput *> original_inputs_links)
+{
+ BLI_assert(original_inputs_links.size() == getNumberOfInputSockets());
+ for (int i = 0; i < original_inputs_links.size(); i++) {
+ NodeOperation *buffer_op = get_input_operation(i);
+ BLI_assert(buffer_op != nullptr);
+ BLI_assert(typeid(*buffer_op) == typeid(BufferOperation));
+ NodeOperationInput *input_socket = getInputSocket(i);
+ input_socket->setLink(original_inputs_links[i]);
+ delete buffer_op;
+ }
+}
+
+/** \} */
+
/*****************
**** OpInput ****
*****************/
@@ -267,6 +440,9 @@ std::ostream &operator<<(std::ostream &os, const NodeOperationFlags &node_operat
if (!node_operation_flags.use_datatype_conversion) {
os << "no_conversion,";
}
+ if (node_operation_flags.is_fullframe_operation) {
+ os << "full_frame,";
+ }
return os;
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index baf3a0878b9..01068c7f812 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -39,6 +39,7 @@ namespace blender::compositor {
class OpenCLDevice;
class ReadBufferOperation;
class WriteBufferOperation;
+class ExecutionSystem;
class NodeOperation;
typedef NodeOperation SocketReader;
@@ -190,6 +191,10 @@ struct NodeOperationFlags {
*/
bool open_cl : 1;
+ /**
+ * TODO: Remove this flag and SingleThreadedOperation if tiled implemention is removed.
+ * Full-frame implemention doesn't need it.
+ */
bool single_threaded : 1;
/**
@@ -232,6 +237,11 @@ struct NodeOperationFlags {
*/
bool use_datatype_conversion : 1;
+ /**
+ * Has this operation fullframe implementation.
+ */
+ bool is_fullframe_operation : 1;
+
NodeOperationFlags()
{
complex = false;
@@ -247,6 +257,7 @@ struct NodeOperationFlags {
is_viewer_operation = false;
is_preview_operation = false;
use_datatype_conversion = true;
+ is_fullframe_operation = false;
}
};
@@ -341,6 +352,13 @@ class NodeOperation {
NodeOperationOutput *getOutputSocket(unsigned int index = 0);
NodeOperationInput *getInputSocket(unsigned int index);
+ NodeOperation *get_input_operation(int index)
+ {
+ /* TODO: Rename protected getInputOperation to get_input_operation and make it public replacing
+ * this method. */
+ return getInputOperation(index);
+ }
+
/**
* \brief determine the resolution of this node
* \note this method will not set the resolution, this is the responsibility of the caller
@@ -537,6 +555,33 @@ class NodeOperation {
return std::unique_ptr<MetaData>();
}
+ /* -------------------------------------------------------------------- */
+ /** \name Full Frame Methods
+ * \{ */
+
+ void render(MemoryBuffer *output_buf,
+ Span<rcti> areas,
+ Span<MemoryBuffer *> inputs_bufs,
+ ExecutionSystem &exec_system);
+
+ /**
+ * Executes operation updating output memory buffer. Single-threaded calls.
+ */
+ virtual void update_memory_buffer(MemoryBuffer *UNUSED(output),
+ const rcti &UNUSED(output_area),
+ Span<MemoryBuffer *> UNUSED(inputs),
+ ExecutionSystem &UNUSED(exec_system))
+ {
+ }
+
+ /**
+ * Get input operation area being read by this operation on rendering given output area.
+ */
+ virtual void get_area_of_interest(int input_op_idx, const rcti &output_area, rcti &r_input_area);
+ void get_area_of_interest(NodeOperation *input_op, const rcti &output_area, rcti &r_input_area);
+
+ /** \} */
+
protected:
NodeOperation();
@@ -616,6 +661,27 @@ class NodeOperation {
{
}
+ private:
+ /* -------------------------------------------------------------------- */
+ /** \name Full Frame Methods
+ * \{ */
+
+ void render_full_frame(MemoryBuffer *output_buf,
+ Span<rcti> areas,
+ Span<MemoryBuffer *> inputs_bufs,
+ ExecutionSystem &exec_system);
+
+ void render_full_frame_fallback(MemoryBuffer *output_buf,
+ Span<rcti> areas,
+ Span<MemoryBuffer *> inputs,
+ ExecutionSystem &exec_system);
+ void render_tile(MemoryBuffer *output_buf, rcti *tile_rect);
+ Vector<NodeOperationOutput *> replace_inputs_with_buffers(Span<MemoryBuffer *> inputs_bufs);
+ void remove_buffers_and_restore_original_inputs(
+ Span<NodeOperationOutput *> original_inputs_links);
+
+ /** \} */
+
/* allow the DebugInfo class to look at internals */
friend class DebugInfo;
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index 82eb969b752..c81a5a2bd98 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -99,8 +99,10 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
determineResolutions();
- /* surround complex ops with read/write buffer */
- add_complex_operation_buffers();
+ if (m_context->get_execution_model() == eExecutionModel::Tiled) {
+ /* surround complex ops with read/write buffer */
+ add_complex_operation_buffers();
+ }
/* links not available from here on */
/* XXX make m_links a local variable to avoid confusion! */
@@ -111,8 +113,10 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
/* ensure topological (link-based) order of nodes */
/*sort_operations();*/ /* not needed yet */
- /* create execution groups */
- group_operations();
+ if (m_context->get_execution_model() == eExecutionModel::Tiled) {
+ /* create execution groups */
+ group_operations();
+ }
/* transfer resulting operations to the system */
system->set_operations(m_operations, m_groups);
diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
new file mode 100644
index 00000000000..4ce674a1c25
--- /dev/null
+++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_SharedOperationBuffers.h"
+#include "BLI_rect.h"
+#include "COM_NodeOperation.h"
+
+namespace blender::compositor {
+
+SharedOperationBuffers::BufferData::BufferData()
+ : buffer(nullptr), registered_reads(0), received_reads(0)
+{
+}
+
+SharedOperationBuffers::BufferData &SharedOperationBuffers::get_buffer_data(NodeOperation *op)
+{
+ return buffers_.lookup_or_add_cb(op, []() { return BufferData(); });
+}
+
+/**
+ * Whether given operation area to render is already registered.
+ * TODO: Possibly refactor to "request_area". Current implementation is incomplete: partial
+ * overlapping, etc. Leading to more rendering than necessary.
+ */
+bool SharedOperationBuffers::is_area_registered(NodeOperation *op, const rcti &area_to_render)
+{
+ BufferData &buf_data = get_buffer_data(op);
+ for (rcti &reg_rect : buf_data.render_areas) {
+ if (BLI_rcti_inside_rcti(&reg_rect, &area_to_render)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Registers an operation area to render.
+ */
+void SharedOperationBuffers::register_area(NodeOperation *op, const rcti &area_to_render)
+{
+ get_buffer_data(op).render_areas.append(area_to_render);
+}
+
+/**
+ * Whether given operation has any registered reads (other operation registered it depends on given
+ * operation).
+ */
+bool SharedOperationBuffers::has_registered_reads(NodeOperation *op)
+{
+ return get_buffer_data(op).registered_reads > 0;
+}
+
+/**
+ * Registers an operation read (other operation depends on given operation).
+ */
+void SharedOperationBuffers::register_read(NodeOperation *read_op)
+{
+ get_buffer_data(read_op).registered_reads++;
+}
+
+/**
+ * Get registered areas given operation needs to render.
+ */
+blender::Span<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op)
+{
+ return get_buffer_data(op).render_areas.as_span();
+}
+
+/**
+ * Whether this operation buffer has already been rendered.
+ */
+bool SharedOperationBuffers::is_operation_rendered(NodeOperation *op)
+{
+ return get_buffer_data(op).buffer != nullptr;
+}
+
+/**
+ * Stores given operation rendered buffer.
+ */
+void SharedOperationBuffers::set_rendered_buffer(NodeOperation *op,
+ std::unique_ptr<MemoryBuffer> buffer)
+{
+ BufferData &buf_data = get_buffer_data(op);
+ BLI_assert(buf_data.received_reads == 0);
+ BLI_assert(buf_data.buffer == nullptr);
+ buf_data.buffer = std::move(buffer);
+}
+
+/**
+ * Get given operation rendered buffer.
+ */
+MemoryBuffer *SharedOperationBuffers::get_rendered_buffer(NodeOperation *op)
+{
+ BLI_assert(is_operation_rendered(op));
+ return get_buffer_data(op).buffer.get();
+}
+
+/**
+ * Reports an operation has finished reading given operation. If all given operation dependencies
+ * have finished its buffer will be disposed.
+ */
+void SharedOperationBuffers::read_finished(NodeOperation *read_op)
+{
+ BufferData &buf_data = get_buffer_data(read_op);
+ buf_data.received_reads++;
+ BLI_assert(buf_data.received_reads > 0 && buf_data.received_reads <= buf_data.registered_reads);
+ if (buf_data.received_reads == buf_data.registered_reads) {
+ /* Dispose buffer. */
+ buf_data.buffer = nullptr;
+ }
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.h b/source/blender/compositor/intern/COM_SharedOperationBuffers.h
new file mode 100644
index 00000000000..480a799d89f
--- /dev/null
+++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "BLI_map.hh"
+#include "BLI_span.hh"
+#include "BLI_vector.hh"
+#include "COM_MemoryBuffer.h"
+#ifdef WITH_CXX_GUARDEDALLOC
+# include "MEM_guardedalloc.h"
+#endif
+#include <memory>
+
+namespace blender::compositor {
+
+/**
+ * Stores and shares operations rendered buffers including render data. Buffers are
+ * disposed once all dependent operations have finished reading them.
+ */
+class SharedOperationBuffers {
+ private:
+ typedef struct BufferData {
+ public:
+ BufferData();
+ std::unique_ptr<MemoryBuffer> buffer;
+ blender::Vector<rcti> render_areas;
+ int registered_reads;
+ int received_reads;
+ } BufferData;
+ blender::Map<NodeOperation *, BufferData> buffers_;
+
+ public:
+ bool is_area_registered(NodeOperation *op, const rcti &area_to_render);
+ void register_area(NodeOperation *op, const rcti &area_to_render);
+
+ bool has_registered_reads(NodeOperation *op);
+ void register_read(NodeOperation *read_op);
+
+ blender::Span<rcti> get_areas_to_render(NodeOperation *op);
+ bool is_operation_rendered(NodeOperation *op);
+ void set_rendered_buffer(NodeOperation *op, std::unique_ptr<MemoryBuffer> buffer);
+ MemoryBuffer *get_rendered_buffer(NodeOperation *op);
+
+ void read_finished(NodeOperation *read_op);
+
+ private:
+ BufferData &get_buffer_data(NodeOperation *op);
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("COM:SharedOperationBuffers")
+#endif
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_TiledExecutionModel.cc b/source/blender/compositor/intern/COM_TiledExecutionModel.cc
new file mode 100644
index 00000000000..d025ce53330
--- /dev/null
+++ b/source/blender/compositor/intern/COM_TiledExecutionModel.cc
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_TiledExecutionModel.h"
+#include "COM_Debug.h"
+#include "COM_ExecutionGroup.h"
+#include "COM_ReadBufferOperation.h"
+#include "COM_WorkScheduler.h"
+
+#include "BLT_translation.h"
+
+#ifdef WITH_CXX_GUARDEDALLOC
+# include "MEM_guardedalloc.h"
+#endif
+
+namespace blender::compositor {
+
+TiledExecutionModel::TiledExecutionModel(CompositorContext &context,
+ Span<NodeOperation *> operations,
+ Span<ExecutionGroup *> groups)
+ : ExecutionModel(context, operations), groups_(groups)
+{
+ const bNodeTree *node_tree = context.getbNodeTree();
+ node_tree->stats_draw(node_tree->sdh, TIP_("Compositing | Determining resolution"));
+
+ unsigned int resolution[2];
+ for (ExecutionGroup *group : groups_) {
+ resolution[0] = 0;
+ resolution[1] = 0;
+ group->determineResolution(resolution);
+
+ if (border_.use_render_border) {
+ const rctf *render_border = border_.viewer_border;
+ group->setRenderBorder(
+ render_border->xmin, render_border->xmax, render_border->ymin, render_border->ymax);
+ }
+
+ if (border_.use_viewer_border) {
+ const rctf *viewer_border = border_.viewer_border;
+ group->setViewerBorder(
+ viewer_border->xmin, viewer_border->xmax, viewer_border->ymin, viewer_border->ymax);
+ }
+ }
+}
+
+static void update_read_buffer_offset(Span<NodeOperation *> operations)
+{
+ unsigned int order = 0;
+ for (NodeOperation *operation : operations) {
+ if (operation->get_flags().is_read_buffer_operation) {
+ ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
+ readOperation->setOffset(order);
+ order++;
+ }
+ }
+}
+
+static void init_write_operations_for_execution(Span<NodeOperation *> operations,
+ const bNodeTree *bTree)
+{
+ for (NodeOperation *operation : operations) {
+ if (operation->get_flags().is_write_buffer_operation) {
+ operation->setbNodeTree(bTree);
+ operation->initExecution();
+ }
+ }
+}
+
+static void link_write_buffers(Span<NodeOperation *> operations)
+{
+ for (NodeOperation *operation : operations) {
+ if (operation->get_flags().is_read_buffer_operation) {
+ ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation);
+ readOperation->updateMemoryBuffer();
+ }
+ }
+}
+
+static void init_non_write_operations_for_execution(Span<NodeOperation *> operations,
+ const bNodeTree *bTree)
+{
+ for (NodeOperation *operation : operations) {
+ if (!operation->get_flags().is_write_buffer_operation) {
+ operation->setbNodeTree(bTree);
+ operation->initExecution();
+ }
+ }
+}
+
+static void init_execution_groups_for_execution(Span<ExecutionGroup *> groups,
+ const int chunk_size)
+{
+ for (ExecutionGroup *execution_group : groups) {
+ execution_group->setChunksize(chunk_size);
+ execution_group->initExecution();
+ }
+}
+
+void TiledExecutionModel::execute(ExecutionSystem &exec_system)
+{
+ const bNodeTree *editingtree = this->context_.getbNodeTree();
+
+ editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Initializing execution"));
+
+ update_read_buffer_offset(operations_);
+
+ init_write_operations_for_execution(operations_, context_.getbNodeTree());
+ link_write_buffers(operations_);
+ init_non_write_operations_for_execution(operations_, context_.getbNodeTree());
+ init_execution_groups_for_execution(groups_, context_.getChunksize());
+
+ WorkScheduler::start(context_);
+ execute_groups(eCompositorPriority::High, exec_system);
+ if (!context_.isFastCalculation()) {
+ execute_groups(eCompositorPriority::Medium, exec_system);
+ execute_groups(eCompositorPriority::Low, exec_system);
+ }
+ WorkScheduler::finish();
+ WorkScheduler::stop();
+
+ editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | De-initializing execution"));
+
+ for (NodeOperation *operation : operations_) {
+ operation->deinitExecution();
+ }
+
+ for (ExecutionGroup *execution_group : groups_) {
+ execution_group->deinitExecution();
+ }
+}
+
+void TiledExecutionModel::execute_groups(eCompositorPriority priority,
+ ExecutionSystem &exec_system)
+{
+ for (ExecutionGroup *execution_group : groups_) {
+ if (execution_group->get_flags().is_output &&
+ execution_group->getRenderPriority() == priority) {
+ execution_group->execute(&exec_system);
+ }
+ }
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_TiledExecutionModel.h b/source/blender/compositor/intern/COM_TiledExecutionModel.h
new file mode 100644
index 00000000000..05a795b9f07
--- /dev/null
+++ b/source/blender/compositor/intern/COM_TiledExecutionModel.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_ExecutionModel.h"
+
+#ifdef WITH_CXX_GUARDEDALLOC
+# include "MEM_guardedalloc.h"
+#endif
+
+namespace blender::compositor {
+
+class ExecutionGroup;
+
+/**
+ * Operations are executed from outputs to inputs grouped in execution groups and rendered in
+ * tiles.
+ */
+class TiledExecutionModel : public ExecutionModel {
+ private:
+ Span<ExecutionGroup *> groups_;
+
+ public:
+ TiledExecutionModel(CompositorContext &context,
+ Span<NodeOperation *> operations,
+ Span<ExecutionGroup *> groups);
+
+ void execute(ExecutionSystem &exec_system) override;
+
+ private:
+ void execute_groups(eCompositorPriority priority, ExecutionSystem &exec_system);
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("COM:TiledExecutionModel")
+#endif
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h
index 28aa746fdc4..4d503022120 100644
--- a/source/blender/compositor/intern/COM_WorkPackage.h
+++ b/source/blender/compositor/intern/COM_WorkPackage.h
@@ -22,6 +22,7 @@
#include "BLI_rect.h"
+#include <functional>
#include <ostream>
namespace blender::compositor {
@@ -33,6 +34,8 @@ class ExecutionGroup;
* \see WorkScheduler
*/
struct WorkPackage {
+ eWorkPackageType type;
+
eWorkPackageState state = eWorkPackageState::NotScheduled;
/**
@@ -50,6 +53,16 @@ struct WorkPackage {
*/
rcti rect;
+ /**
+ * Custom function to execute when work package type is CustomFunction.
+ */
+ std::function<void()> execute_fn;
+
+ /**
+ * Called when work execution is finished.
+ */
+ std::function<void()> executed_fn;
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkPackage")
#endif
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cc b/source/blender/compositor/intern/COM_WorkScheduler.cc
index d578ac24a4a..157ded943d6 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cc
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cc
@@ -98,6 +98,8 @@ static struct {
bool active = false;
bool initialized = false;
} opencl;
+
+ int num_cpu_threads;
} g_work_scheduler;
/* -------------------------------------------------------------------- */
@@ -143,7 +145,8 @@ static void opencl_start(CompositorContext &context)
static bool opencl_schedule(WorkPackage *package)
{
- if (package->execution_group->get_flags().open_cl && g_work_scheduler.opencl.active) {
+ if (package->type == eWorkPackageType::Tile && package->execution_group->get_flags().open_cl &&
+ g_work_scheduler.opencl.active) {
BLI_thread_queue_push(g_work_scheduler.opencl.queue, package);
return true;
}
@@ -532,11 +535,12 @@ void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
opencl_initialize(use_opencl);
}
+ g_work_scheduler.num_cpu_threads = num_cpu_threads;
switch (COM_threading_model()) {
case ThreadingModel::SingleThreaded:
+ g_work_scheduler.num_cpu_threads = 1;
/* Nothing to do. */
break;
-
case ThreadingModel::Queue:
threading_model_queue_initialize(num_cpu_threads);
break;
@@ -568,6 +572,11 @@ void WorkScheduler::deinitialize()
}
}
+int WorkScheduler::get_num_cpu_threads()
+{
+ return g_work_scheduler.num_cpu_threads;
+}
+
int WorkScheduler::current_thread_id()
{
if (COM_threading_model() == ThreadingModel::SingleThreaded) {
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.h b/source/blender/compositor/intern/COM_WorkScheduler.h
index 85b1d7e2ebf..be88859be7c 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.h
+++ b/source/blender/compositor/intern/COM_WorkScheduler.h
@@ -87,6 +87,8 @@ struct WorkScheduler {
*/
static bool has_gpu_devices();
+ static int get_num_cpu_threads();
+
static int current_thread_id();
#ifdef WITH_CXX_GUARDEDALLOC
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
index d97e4371dc6..3beb3aa2917 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
@@ -77,10 +77,10 @@ void CryptomatteBaseNode::convertToOperations(NodeConverter &converter,
/** \name Cryptomatte V2
* \{ */
-static std::string prefix_from_node(const bNode &node)
+static std::string prefix_from_node(const CompositorContext &context, const bNode &node)
{
char prefix[MAX_NAME];
- ntreeCompositCryptomatteLayerPrefix(&node, prefix, sizeof(prefix));
+ ntreeCompositCryptomatteLayerPrefix(context.getScene(), &node, prefix, sizeof(prefix));
return std::string(prefix, BLI_strnlen(prefix, sizeof(prefix)));
}
@@ -119,7 +119,7 @@ void CryptomatteNode::input_operations_from_render_source(
}
const short cryptomatte_layer_id = 0;
- const std::string prefix = prefix_from_node(node);
+ const std::string prefix = prefix_from_node(context, node);
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
if (render_layer) {
@@ -177,7 +177,7 @@ void CryptomatteNode::input_operations_from_image_source(
}
}
- const std::string prefix = prefix_from_node(node);
+ const std::string prefix = prefix_from_node(context, node);
int layer_index;
LISTBASE_FOREACH_INDEX (RenderLayer *, render_layer, &image->rr->layers, layer_index) {
if (!blender::StringRef(prefix).startswith(blender::StringRef(
diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cc b/source/blender/compositor/nodes/COM_TranslateNode.cc
index 922393f006a..1b2ce341a66 100644
--- a/source/blender/compositor/nodes/COM_TranslateNode.cc
+++ b/source/blender/compositor/nodes/COM_TranslateNode.cc
@@ -56,7 +56,10 @@ void TranslateNode::convertToOperations(NodeConverter &converter,
converter.mapInputSocket(inputYSocket, operation->getInputSocket(2));
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
- if (data->wrap_axis) {
+ /* FullFrame does not support using WriteBufferOperation.
+ * TODO: Implement TranslateOperation with wrap support in FullFrame.
+ */
+ if (data->wrap_axis && context.get_execution_model() != eExecutionModel::FullFrame) {
WriteBufferOperation *writeOperation = new WriteBufferOperation(DataType::Color);
WrapOperation *wrapOperation = new WrapOperation(DataType::Color);
wrapOperation->setMemoryProxy(writeOperation->getMemoryProxy());
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc
index e94c457f981..7517ff8a137 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cc
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
@@ -75,16 +75,13 @@ void TextureBaseOperation::deinitExecution()
void TextureBaseOperation::determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2])
{
- if (preferredResolution[0] == 0 || preferredResolution[1] == 0) {
- int width = this->m_rd->xsch * this->m_rd->size / 100;
- int height = this->m_rd->ysch * this->m_rd->size / 100;
- resolution[0] = width;
- resolution[1] = height;
- }
- else {
- resolution[0] = preferredResolution[0];
- resolution[1] = preferredResolution[1];
- }
+ /* Determine inputs resolutions. */
+ unsigned int temp[2];
+ NodeOperation::determineResolution(temp, preferredResolution);
+
+ /* We don't use inputs resolutions because they are only used as parameters, not image data. */
+ resolution[0] = preferredResolution[0];
+ resolution[1] = preferredResolution[1];
}
void TextureAlphaOperation::executePixelSampled(float output[4],
diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h
index e1e04611c6c..e5f56673694 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.h
+++ b/source/blender/compositor/operations/COM_TextureOperation.h
@@ -44,7 +44,7 @@ class TextureBaseOperation : public NodeOperation {
protected:
/**
- * Determine the output resolution. The resolution is retrieved from the Renderer
+ * Determine the output resolution.
*/
void determineResolution(unsigned int resolution[2],
unsigned int preferredResolution[2]) override;
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 0541aa982f3..d6598bf79b0 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -51,7 +51,9 @@ set(INC
set(SRC
intern/draw_cache.c
- intern/draw_cache_extract_mesh.c
+ intern/draw_cache_extract_mesh_extractors.c
+ intern/draw_cache_extract_mesh_render_data.c
+ intern/draw_cache_extract_mesh.cc
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_gpencil.c
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index c8eaa06094e..05496ad4ab0 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -164,8 +164,8 @@ vec3 ensure_valid_reflection(vec3 Ng, vec3 I, vec3 N)
vec2 N_new;
if (valid1 && valid2) {
/* If both are possible, do the expensive reflection-based check. */
- vec2 N1 = vec2(sqrt(1.0 - N1_z2), sqrt(N1_z2));
- vec2 N2 = vec2(sqrt(1.0 - N2_z2), sqrt(N2_z2));
+ vec2 N1 = vec2(safe_sqrt(1.0 - N1_z2), safe_sqrt(N1_z2));
+ vec2 N2 = vec2(safe_sqrt(1.0 - N2_z2), safe_sqrt(N2_z2));
float R1 = 2.0 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz;
float R2 = 2.0 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz;
@@ -181,7 +181,7 @@ vec3 ensure_valid_reflection(vec3 Ng, vec3 I, vec3 N)
}
else if (valid1 || valid2) {
float Nz2 = valid1 ? N1_z2 : N2_z2;
- N_new = vec2(sqrt(1.0 - Nz2), sqrt(Nz2));
+ N_new = vec2(safe_sqrt(1.0 - Nz2), safe_sqrt(Nz2));
}
else {
return Ng;
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
index 7412959a30b..ac48b94fea9 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -442,6 +442,10 @@ void stroke_vertex()
if (is_dot) {
# ifdef GP_MATERIAL_BUFFER_LEN
int alignement = GP_FLAG(m) & GP_STROKE_ALIGNMENT;
+ /* For one point strokes use object aligment. */
+ if (ma.x == -1 && ma2.x == -1 && alignement == GP_STROKE_ALIGNMENT_STROKE) {
+ alignement = GP_STROKE_ALIGNMENT_OBJECT;
+ }
# endif
vec2 x_axis;
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index a3e43ff2ec5..810deaec349 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -24,6 +24,10 @@
struct TaskGraph;
+#include "GPU_batch.h"
+#include "GPU_index_buffer.h"
+#include "GPU_vertex_buffer.h"
+
/* Vertex Group Selection and display options */
typedef struct DRW_MeshWeightState {
int defgroup_active;
@@ -64,13 +68,13 @@ typedef struct DRW_MeshCDMask {
* bit-wise and atomic operations are used to compare and update the struct.
* See `mesh_cd_layers_type_*` functions. */
BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint64_t), "DRW_MeshCDMask exceeds 64 bits")
-
typedef enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
MR_ITER_POLY = 1 << 1,
MR_ITER_LEDGE = 1 << 2,
MR_ITER_LVERT = 1 << 3,
} eMRIterType;
+ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT)
typedef enum eMRDataType {
MR_DATA_POLY_NOR = 1 << 1,
@@ -79,12 +83,11 @@ typedef enum eMRDataType {
/** Force loop normals calculation. */
MR_DATA_TAN_LOOP_NOR = 1 << 4,
} eMRDataType;
+ENUM_OPERATORS(eMRDataType, MR_DATA_TAN_LOOP_NOR)
-typedef enum eMRExtractType {
- MR_EXTRACT_BMESH,
- MR_EXTRACT_MAPPED,
- MR_EXTRACT_MESH,
-} eMRExtractType;
+#ifdef __cplusplus
+extern "C" {
+#endif
BLI_INLINE int mesh_render_mat_len_get(Mesh *me)
{
@@ -150,6 +153,18 @@ typedef struct MeshBufferCache {
GPUIndexBuf **tris_per_mat;
} MeshBufferCache;
+/**
+ * Data that are kept around between extractions to reduce rebuilding time.
+ *
+ * - Loose geometry.
+ */
+typedef struct MeshBufferExtractionCache {
+ int edge_loose_len;
+ int vert_loose_len;
+ int *lverts;
+ int *ledges;
+} MeshBufferExtractionCache;
+
typedef enum DRWBatchFlag {
MBC_SURFACE = (1 << 0),
MBC_SURFACE_WEIGHTS = (1 << 1),
@@ -195,6 +210,10 @@ typedef enum DRWBatchFlag {
typedef struct MeshBatchCache {
MeshBufferCache final, cage, uv_cage;
+ MeshBufferExtractionCache final_extraction_cache;
+ MeshBufferExtractionCache cage_extraction_cache;
+ MeshBufferExtractionCache uv_cage_extraction_cache;
+
struct {
/* Surfaces / Render */
GPUBatch *surface;
@@ -270,7 +289,8 @@ typedef struct MeshBatchCache {
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
- MeshBufferCache mbc,
+ MeshBufferCache *mbc,
+ MeshBufferExtractionCache *extraction_cache,
Mesh *me,
const bool is_editmode,
const bool is_paint_mode,
@@ -279,7 +299,10 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const bool do_final,
const bool do_uvedit,
const bool use_subsurf_fdots,
- const DRW_MeshCDMask *cd_layer_used,
const Scene *scene,
const ToolSettings *ts,
const bool use_hide);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
new file mode 100644
index 00000000000..622ea191a0a
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -0,0 +1,996 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Extraction of Mesh data into VBO to feed to GPU.
+ */
+#include "MEM_guardedalloc.h"
+
+#include "atomic_ops.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_task.h"
+#include "BLI_vector.hh"
+
+#include "BKE_editmesh.h"
+
+#include "GPU_capabilities.h"
+
+#include "draw_cache_extract.h"
+#include "draw_cache_extract_mesh_private.h"
+#include "draw_cache_inline.h"
+
+// #define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
+#define CHUNK_SIZE 8192
+
+namespace blender::draw {
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Elements Extract Struct
+ * \{ */
+
+struct ExtractorRunData {
+ /* Extractor where this run data belongs to. */
+ const MeshExtract *extractor;
+ /* During iteration the VBO/IBO that is being build. */
+ void *buffer = nullptr;
+ /* User data during iteration. Created in MeshExtract.init and passed along to other MeshExtract
+ * functions. */
+ void *user_data = nullptr;
+
+ ExtractorRunData(const MeshExtract *extractor) : extractor(extractor)
+ {
+ }
+};
+
+class ExtractorRunDatas : public Vector<ExtractorRunData> {
+ public:
+ void filter_into(ExtractorRunDatas &result, eMRIterType iter_type) const
+ {
+ for (const ExtractorRunData &data : *this) {
+ const MeshExtract *extractor = data.extractor;
+ if ((iter_type & MR_ITER_LOOPTRI) && extractor->iter_looptri_bm) {
+ BLI_assert(extractor->iter_looptri_mesh);
+ result.append(data);
+ continue;
+ }
+ if ((iter_type & MR_ITER_POLY) && extractor->iter_poly_bm) {
+ BLI_assert(extractor->iter_poly_mesh);
+ result.append(data);
+ continue;
+ }
+ if ((iter_type & MR_ITER_LEDGE) && extractor->iter_ledge_bm) {
+ BLI_assert(extractor->iter_ledge_mesh);
+ result.append(data);
+ continue;
+ }
+ if ((iter_type & MR_ITER_LVERT) && extractor->iter_lvert_bm) {
+ BLI_assert(extractor->iter_lvert_mesh);
+ result.append(data);
+ continue;
+ }
+ }
+ }
+
+ void filter_threaded_extractors_into(ExtractorRunDatas &result)
+ {
+ for (const ExtractorRunData &data : *this) {
+ const MeshExtract *extractor = data.extractor;
+ if (extractor->use_threading) {
+ result.append(extractor);
+ }
+ }
+ }
+
+ eMRIterType iter_types()
+ {
+ eMRIterType iter_type = static_cast<eMRIterType>(0);
+
+ for (const ExtractorRunData &data : *this) {
+ const MeshExtract *extractor = data.extractor;
+ iter_type |= mesh_extract_iter_type(extractor);
+ }
+ return iter_type;
+ }
+
+ eMRDataType data_types()
+ {
+ eMRDataType data_type = static_cast<eMRDataType>(0);
+ for (const ExtractorRunData &data : *this) {
+ const MeshExtract *extractor = data.extractor;
+ data_type |= extractor->data_type;
+ }
+ return data_type;
+ }
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract
+ * \{ */
+
+BLI_INLINE void extract_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ ExtractorRunDatas &extractors,
+ MeshBufferCache *mbc)
+{
+ /* Multi thread. */
+ for (ExtractorRunData &run_data : extractors) {
+ const MeshExtract *extractor = run_data.extractor;
+ run_data.buffer = mesh_extract_buffer_get(extractor, mbc);
+ run_data.user_data = extractor->init(mr, cache, run_data.buffer);
+ }
+}
+
+BLI_INLINE void extract_iter_looptri_bm(const MeshRenderData *mr,
+ const ExtractTriBMesh_Params *params,
+ const ExtractorRunDatas &all_extractors)
+{
+ ExtractorRunDatas extractors;
+ all_extractors.filter_into(extractors, MR_ITER_LOOPTRI);
+
+ EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, elt_index, params)
+ {
+ for (ExtractorRunData &run_data : extractors) {
+ run_data.extractor->iter_looptri_bm(mr, elt, elt_index, run_data.user_data);
+ }
+ }
+ EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
+}
+
+BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr,
+ const ExtractTriMesh_Params *params,
+ const ExtractorRunDatas &all_extractors)
+{
+ ExtractorRunDatas extractors;
+ all_extractors.filter_into(extractors, MR_ITER_LOOPTRI);
+
+ EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, mlt_index, params)
+ {
+ for (ExtractorRunData &run_data : extractors) {
+ run_data.extractor->iter_looptri_mesh(mr, mlt, mlt_index, run_data.user_data);
+ }
+ }
+ EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
+}
+
+BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr,
+ const ExtractPolyBMesh_Params *params,
+ const ExtractorRunDatas &all_extractors)
+{
+ ExtractorRunDatas extractors;
+ all_extractors.filter_into(extractors, MR_ITER_POLY);
+
+ EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
+ {
+ for (ExtractorRunData &run_data : extractors) {
+ run_data.extractor->iter_poly_bm(mr, f, f_index, run_data.user_data);
+ }
+ }
+ EXTRACT_POLY_FOREACH_BM_END;
+}
+
+BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr,
+ const ExtractPolyMesh_Params *params,
+ const ExtractorRunDatas &all_extractors)
+{
+ ExtractorRunDatas extractors;
+ all_extractors.filter_into(extractors, MR_ITER_POLY);
+
+ EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
+ {
+ for (ExtractorRunData &run_data : extractors) {
+ run_data.extractor->iter_poly_mesh(mr, mp, mp_index, run_data.user_data);
+ }
+ }
+ EXTRACT_POLY_FOREACH_MESH_END;
+}
+
+BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr,
+ const ExtractLEdgeBMesh_Params *params,
+ const ExtractorRunDatas &all_extractors)
+{
+ ExtractorRunDatas extractors;
+ all_extractors.filter_into(extractors, MR_ITER_LEDGE);
+
+ EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
+ {
+ for (ExtractorRunData &run_data : extractors) {
+ run_data.extractor->iter_ledge_bm(mr, eed, ledge_index, run_data.user_data);
+ }
+ }
+ EXTRACT_LEDGE_FOREACH_BM_END;
+}
+
+BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr,
+ const ExtractLEdgeMesh_Params *params,
+ const ExtractorRunDatas &all_extractors)
+{
+ ExtractorRunDatas extractors;
+ all_extractors.filter_into(extractors, MR_ITER_LEDGE);
+
+ EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
+ {
+ for (ExtractorRunData &run_data : extractors) {
+ run_data.extractor->iter_ledge_mesh(mr, med, ledge_index, run_data.user_data);
+ }
+ }
+ EXTRACT_LEDGE_FOREACH_MESH_END;
+}
+
+BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr,
+ const ExtractLVertBMesh_Params *params,
+ const ExtractorRunDatas &all_extractors)
+{
+ ExtractorRunDatas extractors;
+ all_extractors.filter_into(extractors, MR_ITER_LVERT);
+
+ EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
+ {
+ for (ExtractorRunData &run_data : extractors) {
+ run_data.extractor->iter_lvert_bm(mr, eve, lvert_index, run_data.user_data);
+ }
+ }
+ EXTRACT_LVERT_FOREACH_BM_END;
+}
+
+BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr,
+ const ExtractLVertMesh_Params *params,
+ const ExtractorRunDatas &all_extractors)
+{
+ ExtractorRunDatas extractors;
+ all_extractors.filter_into(extractors, MR_ITER_LVERT);
+
+ EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
+ {
+ for (ExtractorRunData &run_data : extractors) {
+ run_data.extractor->iter_lvert_mesh(mr, mv, lvert_index, run_data.user_data);
+ }
+ }
+ EXTRACT_LVERT_FOREACH_MESH_END;
+}
+
+BLI_INLINE void extract_finish(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ const ExtractorRunDatas &extractors)
+{
+ for (const ExtractorRunData &run_data : extractors) {
+ const MeshExtract *extractor = run_data.extractor;
+ if (extractor->finish) {
+ extractor->finish(mr, cache, run_data.buffer, run_data.user_data);
+ }
+ }
+}
+
+/* Single Thread. */
+BLI_INLINE void extract_run_and_finish_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ ExtractorRunDatas &extractors,
+ eMRIterType iter_type,
+ MeshBufferCache *mbc)
+{
+ extract_init(mr, cache, extractors, mbc);
+
+ bool is_mesh = mr->extract_type != MR_EXTRACT_BMESH;
+ if (iter_type & MR_ITER_LOOPTRI) {
+ if (is_mesh) {
+ ExtractTriMesh_Params params;
+ params.mlooptri = mr->mlooptri;
+ params.tri_range[0] = 0;
+ params.tri_range[1] = mr->tri_len;
+ extract_iter_looptri_mesh(mr, &params, extractors);
+ }
+ else {
+ ExtractTriBMesh_Params params;
+ params.looptris = mr->edit_bmesh->looptris;
+ params.tri_range[0] = 0;
+ params.tri_range[1] = mr->tri_len;
+ extract_iter_looptri_bm(mr, &params, extractors);
+ }
+ }
+ if (iter_type & MR_ITER_POLY) {
+ if (is_mesh) {
+ ExtractPolyMesh_Params params;
+ params.poly_range[0] = 0;
+ params.poly_range[1] = mr->poly_len;
+ extract_iter_poly_mesh(mr, &params, extractors);
+ }
+ else {
+ ExtractPolyBMesh_Params params;
+ params.poly_range[0] = 0;
+ params.poly_range[1] = mr->poly_len;
+ extract_iter_poly_bm(mr, &params, extractors);
+ }
+ }
+ if (iter_type & MR_ITER_LEDGE) {
+ if (is_mesh) {
+ ExtractLEdgeMesh_Params params;
+ params.ledge = mr->ledges;
+ params.ledge_range[0] = 0;
+ params.ledge_range[1] = mr->edge_loose_len;
+ extract_iter_ledge_mesh(mr, &params, extractors);
+ }
+ else {
+ ExtractLEdgeBMesh_Params params;
+ params.ledge = mr->ledges;
+ params.ledge_range[0] = 0;
+ params.ledge_range[1] = mr->edge_loose_len;
+ extract_iter_ledge_bm(mr, &params, extractors);
+ }
+ }
+ if (iter_type & MR_ITER_LVERT) {
+ if (is_mesh) {
+ ExtractLVertMesh_Params params;
+ params.lvert = mr->lverts;
+ params.lvert_range[0] = 0;
+ params.lvert_range[1] = mr->vert_loose_len;
+ extract_iter_lvert_mesh(mr, &params, extractors);
+ }
+ else {
+ ExtractLVertBMesh_Params params;
+ params.lvert = mr->lverts;
+ params.lvert_range[0] = 0;
+ params.lvert_range[1] = mr->vert_loose_len;
+ extract_iter_lvert_bm(mr, &params, extractors);
+ }
+ }
+ extract_finish(mr, cache, extractors);
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name ExtractTaskData
+ * \{ */
+struct ExtractTaskData {
+ void *next = nullptr;
+ void *prev = nullptr;
+
+ const MeshRenderData *mr = nullptr;
+ MeshBatchCache *cache = nullptr;
+ /* #UserData is shared between the iterations as it holds counters to detect if the
+ * extraction is finished. To make sure the duplication of the user_data does not create a new
+ * instance of the counters we allocate the user_data in its own container.
+ *
+ * This structure makes sure that when extract_init is called, that the user data of all
+ * iterations are updated. */
+
+ ExtractorRunDatas *extractors = nullptr;
+ MeshBufferCache *mbc = nullptr;
+ int32_t *task_counter = nullptr;
+
+ eMRIterType iter_type;
+ int start = 0;
+ int end = INT_MAX;
+ /** Decremented each time a task is finished. */
+
+ ExtractTaskData(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ ExtractorRunDatas *extractors,
+ MeshBufferCache *mbc,
+ int32_t *task_counter)
+ : mr(mr), cache(cache), extractors(extractors), mbc(mbc), task_counter(task_counter)
+ {
+ iter_type = extractors->iter_types();
+ };
+
+ ExtractTaskData(const ExtractTaskData &src) = default;
+
+ ~ExtractTaskData()
+ {
+ delete extractors;
+ }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("DRW:ExtractTaskData")
+#endif
+};
+
+static ExtractTaskData *extract_extract_iter_task_data_create_mesh(const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ ExtractorRunDatas *extractors,
+ MeshBufferCache *mbc,
+ int32_t *task_counter)
+
+{
+ ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors, mbc, task_counter);
+ return taskdata;
+}
+
+static void extract_task_data_free(void *data)
+{
+ ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data);
+ delete task_data;
+}
+
+static void extract_task_data_free_ex(void *data)
+{
+ ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data);
+ task_data->extractors = nullptr;
+ delete task_data;
+}
+
+BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
+ const eMRIterType iter_type,
+ int start,
+ int end,
+ ExtractorRunDatas &extractors)
+{
+ switch (mr->extract_type) {
+ case MR_EXTRACT_BMESH:
+ if (iter_type & MR_ITER_LOOPTRI) {
+ ExtractTriBMesh_Params params;
+ params.looptris = mr->edit_bmesh->looptris;
+ params.tri_range[0] = start;
+ params.tri_range[1] = min_ii(mr->tri_len, end);
+ extract_iter_looptri_bm(mr, &params, extractors);
+ }
+ if (iter_type & MR_ITER_POLY) {
+ ExtractPolyBMesh_Params params;
+ params.poly_range[0] = start;
+ params.poly_range[1] = min_ii(mr->poly_len, end);
+ extract_iter_poly_bm(mr, &params, extractors);
+ }
+ if (iter_type & MR_ITER_LEDGE) {
+ ExtractLEdgeBMesh_Params params;
+ params.ledge = mr->ledges;
+ params.ledge_range[0] = start;
+ params.ledge_range[1] = min_ii(mr->edge_loose_len, end);
+ extract_iter_ledge_bm(mr, &params, extractors);
+ }
+ if (iter_type & MR_ITER_LVERT) {
+ ExtractLVertBMesh_Params params;
+ params.lvert = mr->lverts;
+ params.lvert_range[0] = start;
+ params.lvert_range[1] = min_ii(mr->vert_loose_len, end);
+ extract_iter_lvert_bm(mr, &params, extractors);
+ }
+ break;
+ case MR_EXTRACT_MAPPED:
+ case MR_EXTRACT_MESH:
+ if (iter_type & MR_ITER_LOOPTRI) {
+ ExtractTriMesh_Params params;
+ params.mlooptri = mr->mlooptri;
+ params.tri_range[0] = start;
+ params.tri_range[1] = min_ii(mr->tri_len, end);
+ extract_iter_looptri_mesh(mr, &params, extractors);
+ }
+ if (iter_type & MR_ITER_POLY) {
+ ExtractPolyMesh_Params params;
+ params.poly_range[0] = start;
+ params.poly_range[1] = min_ii(mr->poly_len, end);
+ extract_iter_poly_mesh(mr, &params, extractors);
+ }
+ if (iter_type & MR_ITER_LEDGE) {
+ ExtractLEdgeMesh_Params params;
+ params.ledge = mr->ledges;
+ params.ledge_range[0] = start;
+ params.ledge_range[1] = min_ii(mr->edge_loose_len, end);
+ extract_iter_ledge_mesh(mr, &params, extractors);
+ }
+ if (iter_type & MR_ITER_LVERT) {
+ ExtractLVertMesh_Params params;
+ params.lvert = mr->lverts;
+ params.lvert_range[0] = start;
+ params.lvert_range[1] = min_ii(mr->vert_loose_len, end);
+ extract_iter_lvert_mesh(mr, &params, extractors);
+ }
+ break;
+ }
+}
+
+static void extract_task_init(ExtractTaskData *data)
+{
+ extract_init(data->mr, data->cache, *data->extractors, data->mbc);
+}
+
+static void extract_task_run(void *__restrict taskdata)
+{
+ ExtractTaskData *data = (ExtractTaskData *)taskdata;
+ mesh_extract_iter(data->mr, data->iter_type, data->start, data->end, *data->extractors);
+
+ /* If this is the last task, we do the finish function. */
+ int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
+ if (remainin_tasks == 0) {
+ extract_finish(data->mr, data->cache, *data->extractors);
+ }
+}
+
+static void extract_task_init_and_run(void *__restrict taskdata)
+{
+ ExtractTaskData *data = (ExtractTaskData *)taskdata;
+ extract_run_and_finish_init(
+ data->mr, data->cache, *data->extractors, data->iter_type, data->mbc);
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Task Node - Update Mesh Render Data
+ * \{ */
+struct MeshRenderDataUpdateTaskData {
+ MeshRenderData *mr = nullptr;
+ eMRIterType iter_type;
+ eMRDataType data_flag;
+
+ ~MeshRenderDataUpdateTaskData()
+ {
+ mesh_render_data_free(mr);
+ }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("DRW:MeshRenderDataUpdateTaskData")
+#endif
+};
+
+static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata)
+{
+ BLI_assert(taskdata);
+ delete taskdata;
+}
+
+static void mesh_extract_render_data_node_exec(void *__restrict task_data)
+{
+ MeshRenderDataUpdateTaskData *update_task_data = static_cast<MeshRenderDataUpdateTaskData *>(
+ task_data);
+ MeshRenderData *mr = update_task_data->mr;
+ const eMRIterType iter_type = update_task_data->iter_type;
+ const eMRDataType data_flag = update_task_data->data_flag;
+
+ mesh_render_data_update_normals(mr, data_flag);
+ mesh_render_data_update_looptris(mr, iter_type, data_flag);
+}
+
+static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph,
+ MeshRenderData *mr,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag)
+{
+ MeshRenderDataUpdateTaskData *task_data = new (MeshRenderDataUpdateTaskData);
+ task_data->mr = mr;
+ task_data->iter_type = iter_type;
+ task_data->data_flag = data_flag;
+
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph,
+ mesh_extract_render_data_node_exec,
+ task_data,
+ (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free);
+ return task_node;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Task Node - Extract Single Threaded
+ * \{ */
+
+static struct TaskNode *extract_single_threaded_task_node_create(struct TaskGraph *task_graph,
+ ExtractTaskData *task_data)
+{
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph,
+ extract_task_init_and_run,
+ task_data,
+ (TaskGraphNodeFreeFunction)extract_task_data_free);
+ return task_node;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Task Node - UserData Initializer
+ * \{ */
+struct UserDataInitTaskData {
+ ExtractTaskData *td;
+ int32_t task_counter = 0;
+
+ ~UserDataInitTaskData()
+ {
+ extract_task_data_free(td);
+ }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("DRW:UserDataInitTaskData")
+#endif
+};
+
+static void user_data_init_task_data_free(UserDataInitTaskData *taskdata)
+{
+ delete taskdata;
+}
+
+static void user_data_init_task_data_exec(void *__restrict task_data)
+{
+ UserDataInitTaskData *extract_task_data = static_cast<UserDataInitTaskData *>(task_data);
+ ExtractTaskData *taskdata_base = extract_task_data->td;
+ extract_task_init(taskdata_base);
+}
+
+static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph,
+ UserDataInitTaskData *task_data)
+{
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph,
+ user_data_init_task_data_exec,
+ task_data,
+ (TaskGraphNodeFreeFunction)user_data_init_task_data_free);
+ return task_node;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Extract Loop
+ * \{ */
+
+static void extract_range_task_create(struct TaskGraph *task_graph,
+ struct TaskNode *task_node_user_data_init,
+ ExtractTaskData *taskdata,
+ const eMRIterType type,
+ int start,
+ int length)
+{
+ taskdata = new ExtractTaskData(*taskdata);
+ atomic_add_and_fetch_int32(taskdata->task_counter, 1);
+ taskdata->iter_type = type;
+ taskdata->start = start;
+ taskdata->end = start + length;
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph, extract_task_run, taskdata, extract_task_data_free_ex);
+ BLI_task_graph_edge_create(task_node_user_data_init, task_node);
+}
+
+static int extract_range_task_num_elements_get(const MeshRenderData *mr,
+ const eMRIterType iter_type)
+{
+ /* Divide task into sensible chunks. */
+ int iter_len = 0;
+ if (iter_type & MR_ITER_LOOPTRI) {
+ iter_len += mr->tri_len;
+ }
+ if (iter_type & MR_ITER_POLY) {
+ iter_len += mr->poly_len;
+ }
+ if (iter_type & MR_ITER_LEDGE) {
+ iter_len += mr->edge_loose_len;
+ }
+ if (iter_type & MR_ITER_LVERT) {
+ iter_len += mr->vert_loose_len;
+ }
+ return iter_len;
+}
+
+static int extract_range_task_chunk_size_get(const MeshRenderData *mr,
+ const eMRIterType iter_type,
+ const int num_threads)
+{
+ /* Divide task into sensible chunks. */
+ const int num_elements = extract_range_task_num_elements_get(mr, iter_type);
+ int range_len = (num_elements + num_threads) / num_threads;
+ CLAMP_MIN(range_len, CHUNK_SIZE);
+ return range_len;
+}
+
+static void extract_task_in_ranges_create(struct TaskGraph *task_graph,
+ struct TaskNode *task_node_user_data_init,
+ ExtractTaskData *taskdata_base,
+ const int num_threads)
+{
+ const MeshRenderData *mr = taskdata_base->mr;
+ const int range_len = extract_range_task_chunk_size_get(
+ mr, taskdata_base->iter_type, num_threads);
+
+ if (taskdata_base->iter_type & MR_ITER_LOOPTRI) {
+ for (int i = 0; i < mr->tri_len; i += range_len) {
+ extract_range_task_create(
+ task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LOOPTRI, i, range_len);
+ }
+ }
+ if (taskdata_base->iter_type & MR_ITER_POLY) {
+ for (int i = 0; i < mr->poly_len; i += range_len) {
+ extract_range_task_create(
+ task_graph, task_node_user_data_init, taskdata_base, MR_ITER_POLY, i, range_len);
+ }
+ }
+ if (taskdata_base->iter_type & MR_ITER_LEDGE) {
+ for (int i = 0; i < mr->edge_loose_len; i += range_len) {
+ extract_range_task_create(
+ task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LEDGE, i, range_len);
+ }
+ }
+ if (taskdata_base->iter_type & MR_ITER_LVERT) {
+ for (int i = 0; i < mr->vert_loose_len; i += range_len) {
+ extract_range_task_create(
+ task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LVERT, i, range_len);
+ }
+ }
+}
+
+static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
+ MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ MeshBufferExtractionCache *extraction_cache,
+ Mesh *me,
+
+ const bool is_editmode,
+ const bool is_paint_mode,
+ const bool is_mode_active,
+ const float obmat[4][4],
+ const bool do_final,
+ const bool do_uvedit,
+ const bool use_subsurf_fdots,
+ const Scene *scene,
+ const ToolSettings *ts,
+ const bool use_hide)
+{
+ /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
+ * This sub-graph starts with an extract_render_data_node. This fills/converts the required
+ * data from Mesh.
+ *
+ * Small extractions and extractions that can't be multi-threaded are grouped in a single
+ * `extract_single_threaded_task_node`.
+ *
+ * Other extractions will create a node for each loop exceeding 8192 items. these nodes are
+ * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the
+ * user_data needed for the extraction based on the data extracted from the mesh.
+ * counters are used to check if the finalize of a task has to be called.
+ *
+ * Mesh extraction sub graph
+ *
+ * +----------------------+
+ * +-----> | extract_task1_loop_1 |
+ * | +----------------------+
+ * +------------------+ +----------------------+ +----------------------+
+ * | mesh_render_data | --> | | --> | extract_task1_loop_2 |
+ * +------------------+ | | +----------------------+
+ * | | | +----------------------+
+ * | | user_data_init | --> | extract_task2_loop_1 |
+ * v | | +----------------------+
+ * +------------------+ | | +----------------------+
+ * | single_threaded | | | --> | extract_task2_loop_2 |
+ * +------------------+ +----------------------+ +----------------------+
+ * | +----------------------+
+ * +-----> | extract_task2_loop_3 |
+ * +----------------------+
+ */
+ const bool do_lines_loose_subbuffer = mbc->ibo.lines_loose != nullptr;
+ const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
+ GPU_use_hq_normals_workaround();
+
+ /* Create an array containing all the extractors that needs to be executed. */
+ ExtractorRunDatas extractors;
+
+#define EXTRACT_ADD_REQUESTED(type, type_lowercase, name) \
+ do { \
+ if (DRW_##type_lowercase##_requested(mbc->type_lowercase.name)) { \
+ const MeshExtract *extractor = mesh_extract_override_get( \
+ &extract_##name, do_hq_normals, do_lines_loose_subbuffer); \
+ extractors.append(extractor); \
+ } \
+ } while (0)
+
+ EXTRACT_ADD_REQUESTED(VBO, vbo, pos_nor);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, lnor);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, uv);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, tan);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, vcol);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, sculpt_data);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, orco);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, edge_fac);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, weights);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, edit_data);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_data);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_area);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_angle);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, mesh_analysis);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_pos);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_nor);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_uv);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_edituv_data);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, poly_idx);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, edge_idx);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, vert_idx);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, fdot_idx);
+ EXTRACT_ADD_REQUESTED(VBO, vbo, skin_roots);
+
+ EXTRACT_ADD_REQUESTED(IBO, ibo, tris);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, lines);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, points);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, fdots);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, lines_paint_mask);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, lines_adjacency);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_tris);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_lines);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_points);
+ EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_fdots);
+
+#undef EXTRACT_ADD_REQUESTED
+
+ if (extractors.is_empty()) {
+ return;
+ }
+
+#ifdef DEBUG_TIME
+ double rdata_start = PIL_check_seconds_timer();
+#endif
+
+ eMRIterType iter_type = extractors.iter_types();
+ eMRDataType data_flag = extractors.data_types();
+
+ MeshRenderData *mr = mesh_render_data_create(me,
+ extraction_cache,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ obmat,
+ do_final,
+ do_uvedit,
+ ts,
+ iter_type);
+ mr->use_hide = use_hide;
+ mr->use_subsurf_fdots = use_subsurf_fdots;
+ mr->use_final_mesh = do_final;
+
+#ifdef DEBUG_TIME
+ double rdata_end = PIL_check_seconds_timer();
+#endif
+
+ struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create(
+ task_graph, mr, iter_type, data_flag);
+
+ /* Simple heuristic. */
+ const bool use_thread = (mr->loop_len + mr->loop_loose_len) > CHUNK_SIZE;
+
+ if (use_thread) {
+ uint threads_to_use = 0;
+
+ /* First run the requested extractors that do not support asynchronous ranges. */
+ for (const ExtractorRunData &run_data : extractors) {
+ const MeshExtract *extractor = run_data.extractor;
+ if (!extractor->use_threading) {
+ ExtractorRunDatas *single_threaded_extractors = new ExtractorRunDatas();
+ single_threaded_extractors->append(extractor);
+ ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh(
+ mr, cache, single_threaded_extractors, mbc, nullptr);
+ struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph,
+ taskdata);
+ BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
+ }
+ threads_to_use++;
+ }
+
+ /* Distribute the remaining extractors into ranges per core. */
+ ExtractorRunDatas *multi_threaded_extractors = new ExtractorRunDatas();
+ extractors.filter_threaded_extractors_into(*multi_threaded_extractors);
+ if (!multi_threaded_extractors->is_empty()) {
+ /*
+ * Determine the number of thread to use for multithreading.
+ * Thread can be used for single threaded tasks. These typically take longer to execute so
+ * fill the rest of the threads for range operations.
+ */
+ int num_threads = BLI_task_scheduler_num_threads();
+ if (threads_to_use < num_threads) {
+ num_threads -= threads_to_use;
+ }
+
+ UserDataInitTaskData *user_data_init_task_data = new UserDataInitTaskData();
+ struct TaskNode *task_node_user_data_init = user_data_init_task_node_create(
+ task_graph, user_data_init_task_data);
+
+ user_data_init_task_data->td = extract_extract_iter_task_data_create_mesh(
+ mr, cache, multi_threaded_extractors, mbc, &user_data_init_task_data->task_counter);
+
+ extract_task_in_ranges_create(
+ task_graph, task_node_user_data_init, user_data_init_task_data->td, num_threads);
+
+ BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init);
+ }
+ else {
+ /* No tasks created freeing extractors list. */
+ delete multi_threaded_extractors;
+ }
+ }
+ else {
+ /* Run all requests on the same thread. */
+ ExtractorRunDatas *extractors_copy = new ExtractorRunDatas(extractors);
+ ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh(
+ mr, cache, extractors_copy, mbc, nullptr);
+
+ struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph, taskdata);
+ BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
+ }
+
+ /* Trigger the sub-graph for this mesh. */
+ BLI_task_graph_node_push_work(task_node_mesh_render_data);
+
+#ifdef DEBUG_TIME
+ BLI_task_graph_work_and_wait(task_graph);
+ double end = PIL_check_seconds_timer();
+
+ static double avg = 0;
+ static double avg_fps = 0;
+ static double avg_rdata = 0;
+ static double end_prev = 0;
+
+ if (end_prev == 0) {
+ end_prev = end;
+ }
+
+ avg = avg * 0.95 + (end - rdata_end) * 0.05;
+ avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05;
+ avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05;
+
+ printf(
+ "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000);
+
+ end_prev = end;
+#endif
+}
+
+} // namespace blender::draw
+
+extern "C" {
+void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
+ MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ MeshBufferExtractionCache *extraction_cache,
+ Mesh *me,
+
+ const bool is_editmode,
+ const bool is_paint_mode,
+ const bool is_mode_active,
+ const float obmat[4][4],
+ const bool do_final,
+ const bool do_uvedit,
+ const bool use_subsurf_fdots,
+ const Scene *scene,
+ const ToolSettings *ts,
+ const bool use_hide)
+{
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ mbc,
+ extraction_cache,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ obmat,
+ do_final,
+ do_uvedit,
+ use_subsurf_fdots,
+ scene,
+ ts,
+ use_hide);
+}
+
+} // extern "C"
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
index f167ea3d540..324ebd2ec38 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
@@ -13,7 +13,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
* All rights reserved.
*/
@@ -25,773 +25,94 @@
#include "MEM_guardedalloc.h"
-#include "BLI_alloca.h"
-#include "BLI_bitmap.h"
-#include "BLI_buffer.h"
+#include "atomic_ops.h"
+
+#include "DNA_object_types.h"
+
#include "BLI_edgehash.h"
#include "BLI_jitter_2d.h"
-#include "BLI_math_bits.h"
-#include "BLI_math_vector.h"
+#include "BLI_kdopbvh.h"
#include "BLI_string.h"
-#include "BLI_task.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BKE_bvhutils.h"
-#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_editmesh_tangent.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_mesh_tangent.h"
-#include "BKE_modifier.h"
-#include "BKE_object_deform.h"
#include "BKE_paint.h"
-#include "atomic_ops.h"
-
-#include "bmesh.h"
+#include "ED_uvedit.h"
-#include "GPU_batch.h"
#include "GPU_capabilities.h"
-#include "DRW_render.h"
-
-#include "ED_mesh.h"
-#include "ED_uvedit.h"
-
+#include "draw_cache_extract_mesh_private.h"
#include "draw_cache_impl.h"
-#include "draw_cache_inline.h"
-
-#include "draw_cache_extract.h"
-
-// #define DEBUG_TIME
-#ifdef DEBUG_TIME
-# include "PIL_time_utildefines.h"
-#endif
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
- * \{ */
-
-typedef struct MeshRenderData {
- eMRExtractType extract_type;
-
- int poly_len, edge_len, vert_len, loop_len;
- int edge_loose_len;
- int vert_loose_len;
- int loop_loose_len;
- int tri_len;
- int mat_len;
-
- bool use_hide;
- bool use_subsurf_fdots;
- bool use_final_mesh;
-
- /** Use for #MeshStatVis calculation which use world-space coords. */
- float obmat[4][4];
-
- const ToolSettings *toolsettings;
- /** Edit Mesh */
- BMEditMesh *edit_bmesh;
- BMesh *bm;
- EditMeshData *edit_data;
-
- /* For deformed edit-mesh data. */
- /* Use for #ME_WRAPPER_TYPE_BMESH. */
- const float (*bm_vert_coords)[3];
- const float (*bm_vert_normals)[3];
- const float (*bm_poly_normals)[3];
- const float (*bm_poly_centers)[3];
-
- int *v_origindex, *e_origindex, *p_origindex;
- int crease_ofs;
- int bweight_ofs;
- int freestyle_edge_ofs;
- int freestyle_face_ofs;
- /** Mesh */
- Mesh *me;
- const MVert *mvert;
- const MEdge *medge;
- const MLoop *mloop;
- const MPoly *mpoly;
- BMVert *eve_act;
- BMEdge *eed_act;
- BMFace *efa_act;
- BMFace *efa_act_uv;
- /* Data created on-demand (usually not for #BMesh based data). */
- MLoopTri *mlooptri;
- float (*loop_normals)[3];
- float (*poly_normals)[3];
- int *lverts, *ledges;
-} MeshRenderData;
-
-static void mesh_render_data_update_loose_geom(MeshRenderData *mr,
- const eMRIterType iter_type,
- const eMRDataType UNUSED(data_flag))
-{
- if (mr->extract_type != MR_EXTRACT_BMESH) {
- /* Mesh */
- if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
- mr->vert_loose_len = 0;
- mr->edge_loose_len = 0;
-
- BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
-
- mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__);
- const MEdge *med = mr->medge;
- for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
- if (med->flag & ME_LOOSEEDGE) {
- mr->ledges[mr->edge_loose_len++] = med_index;
- }
- /* Tag verts as not loose. */
- BLI_BITMAP_ENABLE(lvert_map, med->v1);
- BLI_BITMAP_ENABLE(lvert_map, med->v2);
- }
- if (mr->edge_loose_len < mr->edge_len) {
- mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
- }
-
- mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
- for (int v = 0; v < mr->vert_len; v++) {
- if (!BLI_BITMAP_TEST(lvert_map, v)) {
- mr->lverts[mr->vert_loose_len++] = v;
- }
- }
- if (mr->vert_loose_len < mr->vert_len) {
- mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
- }
-
- MEM_freeN(lvert_map);
-
- mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
- }
- }
- else {
- /* #BMesh */
- BMesh *bm = mr->bm;
- if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
- int elem_id;
- BMIter iter;
- BMVert *eve;
- BMEdge *ede;
- mr->vert_loose_len = 0;
- mr->edge_loose_len = 0;
-
- mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
- if (eve->e == NULL) {
- mr->lverts[mr->vert_loose_len++] = elem_id;
- }
- }
- if (mr->vert_loose_len < mr->vert_len) {
- mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
- }
-
- mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__);
- BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
- if (ede->l == NULL) {
- mr->ledges[mr->edge_loose_len++] = elem_id;
- }
- }
- if (mr->edge_loose_len < mr->edge_len) {
- mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
- }
-
- mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
- }
- }
-}
-
-/**
- * Part of the creation of the #MeshRenderData that happens in a thread.
- */
-static void mesh_render_data_update_looptris(MeshRenderData *mr,
- const eMRIterType iter_type,
- const eMRDataType data_flag)
-{
- Mesh *me = mr->me;
- if (mr->extract_type != MR_EXTRACT_BMESH) {
- /* Mesh */
- if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
- mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
- BKE_mesh_recalc_looptri(
- me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri);
- }
- }
- else {
- /* #BMesh */
- if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
- /* Edit mode ensures this is valid, no need to calculate. */
- BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
- }
- }
-}
-
-static void mesh_render_data_update_normals(MeshRenderData *mr,
- const eMRIterType UNUSED(iter_type),
- const eMRDataType data_flag)
-{
- Mesh *me = mr->me;
- const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
- const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
-
- if (mr->extract_type != MR_EXTRACT_BMESH) {
- /* Mesh */
- if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
- mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__);
- BKE_mesh_calc_normals_poly((MVert *)mr->mvert,
- NULL,
- mr->vert_len,
- mr->mloop,
- mr->mpoly,
- mr->loop_len,
- mr->poly_len,
- mr->poly_normals,
- true);
- }
- if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
- mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
- short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
- BKE_mesh_normals_loop_split(mr->me->mvert,
- mr->vert_len,
- mr->me->medge,
- mr->edge_len,
- mr->me->mloop,
- mr->loop_normals,
- mr->loop_len,
- mr->me->mpoly,
- mr->poly_normals,
- mr->poly_len,
- is_auto_smooth,
- split_angle,
- NULL,
- clnors,
- NULL);
- }
- }
- else {
- /* #BMesh */
- if (data_flag & MR_DATA_POLY_NOR) {
- /* Use #BMFace.no instead. */
- }
- if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
-
- const float(*vert_coords)[3] = NULL;
- const float(*vert_normals)[3] = NULL;
- const float(*poly_normals)[3] = NULL;
-
- if (mr->edit_data && mr->edit_data->vertexCos) {
- vert_coords = mr->bm_vert_coords;
- vert_normals = mr->bm_vert_normals;
- poly_normals = mr->bm_poly_normals;
- }
-
- mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
- const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
- BM_loops_calc_normal_vcos(mr->bm,
- vert_coords,
- vert_normals,
- poly_normals,
- is_auto_smooth,
- split_angle,
- mr->loop_normals,
- NULL,
- NULL,
- clnors_offset,
- false);
- }
- }
-}
-
-/**
- * \param is_mode_active: When true, use the modifiers from the edit-data,
- * otherwise don't use modifiers as they are not from this object.
- */
-static MeshRenderData *mesh_render_data_create(Mesh *me,
- const bool is_editmode,
- const bool is_paint_mode,
- const bool is_mode_active,
- const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const DRW_MeshCDMask *UNUSED(cd_used),
- const ToolSettings *ts,
- const eMRIterType iter_type,
- const eMRDataType data_flag)
-{
- MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
- mr->toolsettings = ts;
- mr->mat_len = mesh_render_mat_len_get(me);
-
- copy_m4_m4(mr->obmat, obmat);
-
- if (is_editmode) {
- BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
- mr->bm = me->edit_mesh->bm;
- mr->edit_bmesh = me->edit_mesh;
- mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
- mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
-
- if (mr->edit_data) {
- EditMeshData *emd = mr->edit_data;
- if (emd->vertexCos) {
- BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd);
- BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd);
- }
-
- mr->bm_vert_coords = mr->edit_data->vertexCos;
- mr->bm_vert_normals = mr->edit_data->vertexNos;
- mr->bm_poly_normals = mr->edit_data->polyNos;
- mr->bm_poly_centers = mr->edit_data->polyCos;
- }
-
- bool has_mdata = is_mode_active && (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
- bool use_mapped = is_mode_active &&
- (has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original);
-
- int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;
-
- BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types);
- BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP);
-
- mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false);
- mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true);
- mr->eed_act = BM_mesh_active_edge_get(mr->bm);
- mr->eve_act = BM_mesh_active_vert_get(mr->bm);
-
- mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
- mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT);
-#ifdef WITH_FREESTYLE
- mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE);
- mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE);
-#endif
-
- if (use_mapped) {
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
-
- use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
- }
-
- mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH;
-
- /* Seems like the mesh_eval_final do not have the right origin indices.
- * Force not mapped in this case. */
- if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
- // mr->edit_bmesh = NULL;
- mr->extract_type = MR_EXTRACT_MESH;
- }
- }
- else {
- mr->me = me;
- mr->edit_bmesh = NULL;
-
- bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
- if (use_mapped) {
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
-
- use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
- }
-
- mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH;
- }
-
- if (mr->extract_type != MR_EXTRACT_BMESH) {
- /* Mesh */
- mr->vert_len = mr->me->totvert;
- mr->edge_len = mr->me->totedge;
- mr->loop_len = mr->me->totloop;
- mr->poly_len = mr->me->totpoly;
- mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
-
- mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
- mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
- mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP);
- mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
-
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
- }
- else {
- /* #BMesh */
- BMesh *bm = mr->bm;
-
- mr->vert_len = bm->totvert;
- mr->edge_len = bm->totedge;
- mr->loop_len = bm->totloop;
- mr->poly_len = bm->totface;
- mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
- }
- mesh_render_data_update_loose_geom(mr, iter_type, data_flag);
-
- return mr;
-}
-
-static void mesh_render_data_free(MeshRenderData *mr)
-{
- MEM_SAFE_FREE(mr->mlooptri);
- MEM_SAFE_FREE(mr->poly_normals);
- MEM_SAFE_FREE(mr->loop_normals);
-
- MEM_SAFE_FREE(mr->lverts);
- MEM_SAFE_FREE(mr->ledges);
-
- MEM_freeN(mr);
-}
-
-BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
+void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc)
{
- return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
- BM_face_at_index(mr->bm, mr->p_origindex[idx]) :
- NULL;
+ /* NOTE: POINTER_OFFSET on windows platforms casts internally to `void *`, but on GCC/CLANG to
+ * `MeshBufferCache *`. What shows a different usage versus intent. */
+ void **buffer_ptr = (void **)POINTER_OFFSET(mbc, extractor->mesh_buffer_offset);
+ void *buffer = *buffer_ptr;
+ BLI_assert(buffer);
+ return buffer;
}
-BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx)
+eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
{
- return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
- BM_edge_at_index(mr->bm, mr->e_origindex[idx]) :
- NULL;
+ eMRIterType type = 0;
+ SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
+ SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY);
+ SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE);
+ SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT);
+ return type;
}
-BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
-{
- return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
- BM_vert_at_index(mr->bm, mr->v_origindex[idx]) :
- NULL;
-}
+/* ---------------------------------------------------------------------- */
+/** \name Override extractors
+ * Extractors can be overridden. When overridden a specialized version is used. The next functions
+ * would check for any needed overrides and usage of the specialized version.
+ * \{ */
-BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
+static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *extractor)
{
- const float(*vert_coords)[3] = mr->bm_vert_coords;
- if (vert_coords != NULL) {
- return vert_coords[BM_elem_index_get(eve)];
+ if (extractor == &extract_pos_nor) {
+ return &extract_pos_nor_hq;
}
-
- UNUSED_VARS(mr);
- return eve->co;
-}
-
-BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
-{
- const float(*vert_normals)[3] = mr->bm_vert_normals;
- if (vert_normals != NULL) {
- return vert_normals[BM_elem_index_get(eve)];
+ if (extractor == &extract_lnor) {
+ return &extract_lnor_hq;
}
-
- UNUSED_VARS(mr);
- return eve->no;
+ if (extractor == &extract_tan) {
+ return &extract_tan_hq;
+ }
+ if (extractor == &extract_fdots_nor) {
+ return &extract_fdots_nor_hq;
+ }
+ return extractor;
}
-BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
+static const MeshExtract *mesh_extract_override_loose_lines(const MeshExtract *extractor)
{
- const float(*poly_normals)[3] = mr->bm_poly_normals;
- if (poly_normals != NULL) {
- return poly_normals[BM_elem_index_get(efa)];
+ if (extractor == &extract_lines) {
+ return &extract_lines_with_lines_loose;
}
-
- UNUSED_VARS(mr);
- return efa->no;
+ return extractor;
}
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract: Loop Triangles
- * \{ */
-
-typedef struct ExtractTriBMesh_Params {
- BMLoop *(*looptris)[3];
- int tri_range[2];
-} ExtractTriBMesh_Params;
-typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
- const ExtractTriBMesh_Params *params,
- void *data);
-
-#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \
- CHECK_TYPE(params, const ExtractTriBMesh_Params *); \
- { \
- const int _tri_index_end = (params)->tri_range[1]; \
- BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \
- for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
- index_tri += 1, elem_tri += 3)
-#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END }
-
-typedef struct ExtractTriMesh_Params {
- const MLoopTri *mlooptri;
- int tri_range[2];
-} ExtractTriMesh_Params;
-typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
- const ExtractTriMesh_Params *params,
- void *data);
-
-#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \
- CHECK_TYPE(params, const ExtractTriMesh_Params *); \
- { \
- const int _tri_index_end = (params)->tri_range[1]; \
- const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \
- for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
- index_tri += 1, elem_tri += 1)
-#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END }
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract: Polygons, Loops
- * \{ */
-
-typedef struct ExtractPolyBMesh_Params {
- BMLoop *(*looptris)[3];
- int poly_range[2];
-} ExtractPolyBMesh_Params;
-typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
- void *data);
-
-#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \
- CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
- { \
- BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
- BMFace **_ftable = mr->bm->ftable; \
- const int _poly_index_end = (params)->poly_range[1]; \
- for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
- index_poly += 1) { \
- BMFace *elem_poly = _ftable[index_poly]; \
- (void)elem_poly;
-
-#define EXTRACT_POLY_FOREACH_BM_END \
- } \
- }
-
-/* Iterate over polygon and loop. */
-#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \
- CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
- { \
- BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
- BMFace **_ftable = mr->bm->ftable; \
- const int _poly_index_end = (params)->poly_range[1]; \
- for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
- index_poly += 1) { \
- BMFace *elem_face = _ftable[index_poly]; \
- BMLoop *elem_loop, *l_first; \
- elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \
- do { \
- const int index_loop = BM_elem_index_get(elem_loop); \
- (void)index_loop; /* Quiet warning when unused. */
-
-#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \
- } \
- while ((elem_loop = elem_loop->next) != l_first) \
- ; \
- } \
- }
-
-typedef struct ExtractPolyMesh_Params {
- int poly_range[2];
-} ExtractPolyMesh_Params;
-typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
- void *data);
-
-#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \
- CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
- { \
- const MPoly *_mpoly = mr->mpoly; \
- const int _poly_index_end = (params)->poly_range[1]; \
- for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
- index_poly += 1) { \
- const MPoly *elem_poly = &_mpoly[index_poly]; \
- (void)elem_poly;
-
-#define EXTRACT_POLY_FOREACH_MESH_END \
- } \
- }
-
-/* Iterate over polygon and loop. */
-#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \
- elem_poly, index_poly, elem_loop, index_loop, params, mr) \
- CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
- { \
- const MPoly *_mpoly = mr->mpoly; \
- const MLoop *_mloop = mr->mloop; \
- const int _poly_index_end = (params)->poly_range[1]; \
- for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
- index_poly += 1) { \
- const MPoly *elem_poly = &_mpoly[index_poly]; \
- const int _index_end = elem_poly->loopstart + elem_poly->totloop; \
- for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \
- const MLoop *elem_loop = &_mloop[index_loop]; \
- (void)elem_loop;
-
-#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \
- } \
- } \
- }
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract: Loose Edges
- * \{ */
-
-typedef struct ExtractLEdgeBMesh_Params {
- const int *ledge;
- int ledge_range[2];
-} ExtractLEdgeBMesh_Params;
-typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
- void *data);
-
-#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \
- CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \
- { \
- BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \
- BMEdge **_etable = mr->bm->etable; \
- const int *_ledge = (params)->ledge; \
- const int _ledge_index_end = (params)->ledge_range[1]; \
- for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
- index_ledge += 1) { \
- BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \
- (void)elem_edge; /* Quiet warning when unused. */ \
- {
-#define EXTRACT_LEDGE_FOREACH_BM_END \
- } \
- } \
- }
-
-typedef struct ExtractLEdgeMesh_Params {
- const int *ledge;
- int ledge_range[2];
-} ExtractLEdgeMesh_Params;
-typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
- void *data);
-
-#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \
- CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \
- { \
- const MEdge *_medge = mr->medge; \
- const int *_ledge = (params)->ledge; \
- const int _ledge_index_end = (params)->ledge_range[1]; \
- for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
- index_ledge += 1) { \
- const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \
- (void)elem_edge; /* Quiet warning when unused. */ \
- {
-#define EXTRACT_LEDGE_FOREACH_MESH_END \
- } \
- } \
+const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
+ const bool do_hq_normals,
+ const bool do_lines_loose_subbuffer)
+{
+ if (do_hq_normals) {
+ extractor = mesh_extract_override_hq_normals(extractor);
}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract: Loose Vertices
- * \{ */
-
-typedef struct ExtractLVertBMesh_Params {
- const int *lvert;
- int lvert_range[2];
-} ExtractLVertBMesh_Params;
-typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
- const ExtractLVertBMesh_Params *params,
- void *data);
-
-#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \
- CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \
- { \
- BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
- BMVert **vtable = mr->bm->vtable; \
- const int *lverts = (params)->lvert; \
- const int _lvert_index_end = (params)->lvert_range[1]; \
- for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
- index_lvert += 1) { \
- BMVert *elem_vert = vtable[lverts[index_lvert]]; \
- (void)elem_vert; /* Quiet warning when unused. */ \
- {
-#define EXTRACT_LVERT_FOREACH_BM_END \
- } \
- } \
- }
-
-typedef struct ExtractLVertMesh_Params {
- const int *lvert;
- int lvert_range[2];
-} ExtractLVertMesh_Params;
-typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
- const ExtractLVertMesh_Params *params,
- void *data);
-
-#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \
- CHECK_TYPE(params, const ExtractLVertMesh_Params *); \
- { \
- const MVert *mvert = mr->mvert; \
- const int *lverts = (params)->lvert; \
- const int _lvert_index_end = (params)->lvert_range[1]; \
- for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
- index_lvert += 1) { \
- const MVert *elem = &mvert[lverts[index_lvert]]; \
- (void)elem; /* Quiet warning when unused. */ \
- {
-#define EXTRACT_LVERT_FOREACH_MESH_END \
- } \
- } \
+ if (do_lines_loose_subbuffer) {
+ extractor = mesh_extract_override_loose_lines(extractor);
}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Mesh Elements Extract Struct
- * \{ */
-
-typedef void *(ExtractInitFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer);
-typedef void(ExtractFinishFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer,
- void *data);
-
-typedef struct MeshExtract {
- /** Executed on main thread and return user data for iteration functions. */
- ExtractInitFn *init;
- /** Executed on one (or more if use_threading) worker thread(s). */
- ExtractTriBMeshFn *iter_looptri_bm;
- ExtractTriMeshFn *iter_looptri_mesh;
- ExtractPolyBMeshFn *iter_poly_bm;
- ExtractPolyMeshFn *iter_poly_mesh;
- ExtractLEdgeBMeshFn *iter_ledge_bm;
- ExtractLEdgeMeshFn *iter_ledge_mesh;
- ExtractLVertBMeshFn *iter_lvert_bm;
- ExtractLVertMeshFn *iter_lvert_mesh;
- /** Executed on one worker thread after all elements iterations. */
- ExtractFinishFn *finish;
- /** Used to request common data. */
- const eMRDataType data_flag;
- /** Used to know if the element callbacks are thread-safe and can be parallelized. */
- const bool use_threading;
-} MeshExtract;
-
-BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
-{
- eMRIterType type = 0;
- SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
- SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY);
- SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE);
- SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT);
- return type;
+ return extractor;
}
/** \} */
@@ -855,69 +176,65 @@ static void *extract_tris_init(const MeshRenderData *mr,
}
static void extract_tris_iter_looptri_bm(const MeshRenderData *mr,
- const struct ExtractTriBMesh_Params *params,
+ BMLoop **elt,
+ const int UNUSED(elt_index),
void *_data)
{
MeshExtract_Tri_Data *data = _data;
const int mat_last = mr->mat_len - 1;
- EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params)
- {
- if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
- int *mat_tri_ofs = data->tri_mat_end;
- const int mat = min_ii(elt[0]->f->mat_nr, mat_last);
- GPU_indexbuf_set_tri_verts(&data->elb,
- mat_tri_ofs[mat]++,
- BM_elem_index_get(elt[0]),
- BM_elem_index_get(elt[1]),
- BM_elem_index_get(elt[2]));
- }
+
+ if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
+ int *mat_tri_ofs = data->tri_mat_end;
+ const int mat = min_ii(elt[0]->f->mat_nr, mat_last);
+ GPU_indexbuf_set_tri_verts(&data->elb,
+ mat_tri_ofs[mat]++,
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]));
}
- EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
}
static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr,
- const struct ExtractTriMesh_Params *params,
+ const MLoopTri *mlt,
+ const int UNUSED(elt_index),
void *_data)
{
MeshExtract_Tri_Data *data = _data;
const int mat_last = mr->mat_len - 1;
- EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params)
- {
- const MPoly *mp = &mr->mpoly[mlt->poly];
- if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
- int *mat_tri_ofs = data->tri_mat_end;
- const int mat = min_ii(mp->mat_nr, mat_last);
- GPU_indexbuf_set_tri_verts(
- &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
- }
+ const MPoly *mp = &mr->mpoly[mlt->poly];
+ if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
+ int *mat_tri_ofs = data->tri_mat_end;
+ const int mat = min_ii(mp->mat_nr, mat_last);
+ GPU_indexbuf_set_tri_verts(
+ &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
}
- EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
}
static void extract_tris_finish(const MeshRenderData *mr,
struct MeshBatchCache *cache,
- void *ibo,
+ void *buf,
void *_data)
{
+ GPUIndexBuf *ibo = buf;
MeshExtract_Tri_Data *data = _data;
GPU_indexbuf_build_in_place(&data->elb, ibo);
/* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
* is created before the surfaces-per-material. */
if (mr->use_final_mesh && cache->final.tris_per_mat) {
- MeshBufferCache *mbc = &cache->final;
+ MeshBufferCache *mbc_final = &cache->final;
for (int i = 0; i < mr->mat_len; i++) {
/* These IBOs have not been queried yet but we create them just in case they are needed
* later since they are not tracked by mesh_buffer_cache_create_requested(). */
- if (mbc->tris_per_mat[i] == NULL) {
- mbc->tris_per_mat[i] = GPU_indexbuf_calloc();
+ if (mbc_final->tris_per_mat[i] == NULL) {
+ mbc_final->tris_per_mat[i] = GPU_indexbuf_calloc();
}
/* Multiply by 3 because these are triangle indices. */
const int mat_start = data->tri_mat_start[i];
const int mat_end = data->tri_mat_end[i];
const int start = mat_start * 3;
const int len = (mat_end - mat_start) * 3;
- GPU_indexbuf_create_subrange_in_place(mbc->tris_per_mat[i], ibo, start, len);
+ GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len);
}
}
MEM_freeN(data->tri_mat_start);
@@ -925,14 +242,13 @@ static void extract_tris_finish(const MeshRenderData *mr,
MEM_freeN(data);
}
-static const MeshExtract extract_tris = {
- .init = extract_tris_init,
- .iter_looptri_bm = extract_tris_iter_looptri_bm,
- .iter_looptri_mesh = extract_tris_iter_looptri_mesh,
- .finish = extract_tris_finish,
- .data_flag = 0,
- .use_threading = false,
-};
+const MeshExtract extract_tris = {.init = extract_tris_init,
+ .iter_looptri_bm = extract_tris_iter_looptri_bm,
+ .iter_looptri_mesh = extract_tris_iter_looptri_mesh,
+ .finish = extract_tris_finish,
+ .data_type = 0,
+ .use_threading = false,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris)};
/** \} */
@@ -951,134 +267,118 @@ static void *extract_lines_init(const MeshRenderData *mr,
return elb;
}
-static void extract_lines_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *elb)
{
- /* Using poly & loop iterator would complicate accessing the adjacent loop. */
- EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
- {
- BMLoop *l_iter, *l_first;
- /* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev;
- do {
- if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) {
- GPU_indexbuf_set_line_verts(elb,
- BM_elem_index_get(l_iter->e),
- BM_elem_index_get(l_iter),
- BM_elem_index_get(l_iter->next));
- }
- else {
- GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e));
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
- EXTRACT_POLY_FOREACH_BM_END;
+ BMLoop *l_iter, *l_first;
+ /* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev;
+ do {
+ if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_line_verts(elb,
+ BM_elem_index_get(l_iter->e),
+ BM_elem_index_get(l_iter),
+ BM_elem_index_get(l_iter->next));
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e));
+ }
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_lines_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *elb)
{
/* Using poly & loop iterator would complicate accessing the adjacent loop. */
const MLoop *mloop = mr->mloop;
const MEdge *medge = mr->medge;
if (mr->use_hide || (mr->extract_type == MR_EXTRACT_MAPPED) || (mr->e_origindex != NULL)) {
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- const int ml_index_last = mp->loopstart + (mp->totloop - 1);
- int ml_index = ml_index_last, ml_index_next = mp->loopstart;
- do {
- const MLoop *ml = &mloop[ml_index];
- const MEdge *med = &medge[ml->e];
- if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
- ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
- (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) {
- GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
- }
- else {
- GPU_indexbuf_set_line_restart(elb, ml->e);
- }
- } while ((ml_index = ml_index_next++) != ml_index_last);
- }
- EXTRACT_POLY_FOREACH_MESH_END;
+ const int ml_index_last = mp->loopstart + (mp->totloop - 1);
+ int ml_index = ml_index_last, ml_index_next = mp->loopstart;
+ do {
+ const MLoop *ml = &mloop[ml_index];
+ const MEdge *med = &medge[ml->e];
+ if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
+ (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) {
+ GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, ml->e);
+ }
+ } while ((ml_index = ml_index_next++) != ml_index_last);
}
else {
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- const int ml_index_last = mp->loopstart + (mp->totloop - 1);
- int ml_index = ml_index_last, ml_index_next = mp->loopstart;
- do {
- const MLoop *ml = &mloop[ml_index];
- GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
- } while ((ml_index = ml_index_next++) != ml_index_last);
- }
- EXTRACT_POLY_FOREACH_MESH_END;
+ const int ml_index_last = mp->loopstart + (mp->totloop - 1);
+ int ml_index = ml_index_last, ml_index_next = mp->loopstart;
+ do {
+ const MLoop *ml = &mloop[ml_index];
+ GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
+ } while ((ml_index = ml_index_next++) != ml_index_last);
}
}
static void extract_lines_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
+ BMEdge *eed,
+ const int ledge_index,
void *elb)
{
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- const int l_index_offset = mr->edge_len + ledge_index;
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- const int l_index = mr->loop_len + ledge_index * 2;
- GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
- }
- else {
- GPU_indexbuf_set_line_restart(elb, l_index_offset);
- }
- /* Don't render the edge twice. */
- GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed));
+ const int l_index_offset = mr->edge_len + ledge_index;
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ const int l_index = mr->loop_len + ledge_index * 2;
+ GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
}
- EXTRACT_LEDGE_FOREACH_BM_END;
+ else {
+ GPU_indexbuf_set_line_restart(elb, l_index_offset);
+ }
+ /* Don't render the edge twice. */
+ GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed));
}
static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
+ const MEdge *med,
+ const uint ledge_index,
void *elb)
{
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- const int l_index_offset = mr->edge_len + ledge_index;
- const int e_index = mr->ledges[ledge_index];
- if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
- ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
- (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) {
- const int l_index = mr->loop_len + ledge_index * 2;
- GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
- }
- else {
- GPU_indexbuf_set_line_restart(elb, l_index_offset);
- }
- /* Don't render the edge twice. */
- GPU_indexbuf_set_line_restart(elb, e_index);
+ const int l_index_offset = mr->edge_len + ledge_index;
+ const int e_index = mr->ledges[ledge_index];
+ if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
+ (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) {
+ const int l_index = mr->loop_len + ledge_index * 2;
+ GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
+ }
+ else {
+ GPU_indexbuf_set_line_restart(elb, l_index_offset);
}
- EXTRACT_LEDGE_FOREACH_MESH_END;
+ /* Don't render the edge twice. */
+ GPU_indexbuf_set_line_restart(elb, e_index);
}
static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *ibo,
+ void *buf,
void *elb)
{
+ GPUIndexBuf *ibo = buf;
GPU_indexbuf_build_in_place(elb, ibo);
MEM_freeN(elb);
}
-static const MeshExtract extract_lines = {
- .init = extract_lines_init,
- .iter_poly_bm = extract_lines_iter_poly_bm,
- .iter_poly_mesh = extract_lines_iter_poly_mesh,
- .iter_ledge_bm = extract_lines_iter_ledge_bm,
- .iter_ledge_mesh = extract_lines_iter_ledge_mesh,
- .finish = extract_lines_finish,
- .data_flag = 0,
- .use_threading = false,
-};
+const MeshExtract extract_lines = {.init = extract_lines_init,
+ .iter_poly_bm = extract_lines_iter_poly_bm,
+ .iter_poly_mesh = extract_lines_iter_poly_mesh,
+ .iter_ledge_bm = extract_lines_iter_ledge_bm,
+ .iter_ledge_mesh = extract_lines_iter_ledge_mesh,
+ .finish = extract_lines_finish,
+ .data_type = 0,
+ .use_threading = false,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines)};
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -1098,24 +398,25 @@ static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshB
static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
struct MeshBatchCache *cache,
- void *ibo,
+ void *buf,
void *elb)
{
+ GPUIndexBuf *ibo = buf;
GPU_indexbuf_build_in_place(elb, ibo);
extract_lines_loose_subbuffer(mr, cache);
MEM_freeN(elb);
}
-static const MeshExtract extract_lines_with_lines_loose = {
+const MeshExtract extract_lines_with_lines_loose = {
.init = extract_lines_init,
.iter_poly_bm = extract_lines_iter_poly_bm,
.iter_poly_mesh = extract_lines_iter_poly_mesh,
.iter_ledge_bm = extract_lines_iter_ledge_bm,
.iter_ledge_mesh = extract_lines_iter_ledge_mesh,
.finish = extract_lines_with_lines_loose_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines)};
/** \} */
@@ -1159,97 +460,91 @@ BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb,
}
}
-static void extract_points_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_points_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *elb)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- vert_set_bm(elb, l->v, l_index);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+
+ vert_set_bm(elb, l_iter->v, l_index);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_points_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *elb)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
vert_set_mesh(elb, mr, ml->v, ml_index);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_points_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
+ BMEdge *eed,
+ const int ledge_index,
void *elb)
{
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2));
- vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1);
- }
- EXTRACT_LEDGE_FOREACH_BM_END;
+ vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2));
+ vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1);
}
static void extract_points_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
+ const MEdge *med,
+ const uint ledge_index,
void *elb)
{
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2));
- vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1);
- }
- EXTRACT_LEDGE_FOREACH_MESH_END;
+ vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2));
+ vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1);
}
static void extract_points_iter_lvert_bm(const MeshRenderData *mr,
- const ExtractLVertBMesh_Params *params,
+ BMVert *eve,
+ const int lvert_index,
void *elb)
{
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
- {
- vert_set_bm(elb, eve, offset + lvert_index);
- }
- EXTRACT_LVERT_FOREACH_BM_END;
+ vert_set_bm(elb, eve, offset + lvert_index);
}
static void extract_points_iter_lvert_mesh(const MeshRenderData *mr,
- const ExtractLVertMesh_Params *params,
+ const MVert *UNUSED(mv),
+ const int lvert_index,
void *elb)
{
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
- {
- vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index);
- }
- EXTRACT_LVERT_FOREACH_MESH_END;
+
+ vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index);
}
static void extract_points_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *ibo,
+ void *buf,
void *elb)
{
+ GPUIndexBuf *ibo = buf;
GPU_indexbuf_build_in_place(elb, ibo);
MEM_freeN(elb);
}
-static const MeshExtract extract_points = {
- .init = extract_points_init,
- .iter_poly_bm = extract_points_iter_poly_bm,
- .iter_poly_mesh = extract_points_iter_poly_mesh,
- .iter_ledge_bm = extract_points_iter_ledge_bm,
- .iter_ledge_mesh = extract_points_iter_ledge_mesh,
- .iter_lvert_bm = extract_points_iter_lvert_bm,
- .iter_lvert_mesh = extract_points_iter_lvert_mesh,
- .finish = extract_points_finish,
- .data_flag = 0,
- .use_threading = false,
-};
+const MeshExtract extract_points = {.init = extract_points_init,
+ .iter_poly_bm = extract_points_iter_poly_bm,
+ .iter_poly_mesh = extract_points_iter_poly_mesh,
+ .iter_ledge_bm = extract_points_iter_ledge_bm,
+ .iter_ledge_mesh = extract_points_iter_ledge_mesh,
+ .iter_lvert_bm = extract_points_iter_lvert_bm,
+ .iter_lvert_mesh = extract_points_iter_lvert_mesh,
+ .finish = extract_points_finish,
+ .data_type = 0,
+ .use_threading = false,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.points)};
/** \} */
@@ -1266,71 +561,65 @@ static void *extract_fdots_init(const MeshRenderData *mr,
return elb;
}
-static void extract_fdots_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int f_index,
void *elb)
{
- EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
- {
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- GPU_indexbuf_set_point_vert(elb, f_index, f_index);
- }
- else {
- GPU_indexbuf_set_point_restart(elb, f_index);
- }
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_set_point_vert(elb, f_index, f_index);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, f_index);
}
- EXTRACT_POLY_FOREACH_BM_END;
}
static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *elb)
{
if (mr->use_subsurf_fdots) {
/* Check #ME_VERT_FACEDOT. */
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
const MVert *mv = &mr->mvert[ml->v];
if ((mv->flag & ME_VERT_FACEDOT) && !(mr->use_hide && (mp->flag & ME_HIDE))) {
GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
- }
- else {
- GPU_indexbuf_set_point_restart(elb, mp_index);
+ return;
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
+ GPU_indexbuf_set_point_restart(elb, mp_index);
}
else {
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
- GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
- }
- else {
- GPU_indexbuf_set_point_restart(elb, mp_index);
- }
+ if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
+ GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
+ }
+ else {
+ GPU_indexbuf_set_point_restart(elb, mp_index);
}
- EXTRACT_POLY_FOREACH_MESH_END;
}
}
static void extract_fdots_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *ibo,
+ void *buf,
void *elb)
{
+ GPUIndexBuf *ibo = buf;
GPU_indexbuf_build_in_place(elb, ibo);
MEM_freeN(elb);
}
-static const MeshExtract extract_fdots = {
- .init = extract_fdots_init,
- .iter_poly_bm = extract_fdots_iter_poly_bm,
- .iter_poly_mesh = extract_fdots_iter_poly_mesh,
- .finish = extract_fdots_finish,
- .data_flag = 0,
- .use_threading = false,
-};
+const MeshExtract extract_fdots = {.init = extract_fdots_init,
+ .iter_poly_bm = extract_fdots_iter_poly_bm,
+ .iter_poly_mesh = extract_fdots_iter_poly_mesh,
+ .finish = extract_fdots_finish,
+ .data_type = 0,
+ .use_threading = false,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.fdots)};
/** \} */
@@ -1346,7 +635,7 @@ typedef struct MeshExtract_LinePaintMask_Data {
static void *extract_lines_paint_mask_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(buf))
+ void *UNUSED(ibo))
{
size_t bitmap_size = BLI_BITMAP_SIZE(mr->edge_len);
MeshExtract_LinePaintMask_Data *data = MEM_callocN(sizeof(*data) + bitmap_size, __func__);
@@ -1355,12 +644,16 @@ static void *extract_lines_paint_mask_init(const MeshRenderData *mr,
}
static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *_data)
{
MeshExtract_LinePaintMask_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+
const int e_index = ml->e;
const MEdge *me = &mr->medge[e_index];
if (!((mr->use_hide && (me->flag & ME_HIDE)) ||
@@ -1390,26 +683,26 @@ static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr,
GPU_indexbuf_set_line_restart(&data->elb, e_index);
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
+
static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *ibo,
+ void *buf,
void *_data)
{
+ GPUIndexBuf *ibo = buf;
MeshExtract_LinePaintMask_Data *data = _data;
-
GPU_indexbuf_build_in_place(&data->elb, ibo);
MEM_freeN(data);
}
-static const MeshExtract extract_lines_paint_mask = {
+const MeshExtract extract_lines_paint_mask = {
.init = extract_lines_paint_mask_init,
.iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh,
.finish = extract_lines_paint_mask_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_paint_mask)};
/** \} */
@@ -1487,49 +780,44 @@ BLI_INLINE void lines_adjacency_triangle(
}
static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
- const struct ExtractTriBMesh_Params *params,
+ BMLoop **elt,
+ const int UNUSED(elt_index),
void *data)
{
- EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params)
- {
- if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
- lines_adjacency_triangle(BM_elem_index_get(elt[0]->v),
- BM_elem_index_get(elt[1]->v),
- BM_elem_index_get(elt[2]->v),
- BM_elem_index_get(elt[0]),
- BM_elem_index_get(elt[1]),
- BM_elem_index_get(elt[2]),
- data);
- }
+ if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
+ lines_adjacency_triangle(BM_elem_index_get(elt[0]->v),
+ BM_elem_index_get(elt[1]->v),
+ BM_elem_index_get(elt[2]->v),
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]),
+ data);
}
- EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
}
static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr,
- const struct ExtractTriMesh_Params *params,
+ const MLoopTri *mlt,
+ const int UNUSED(elt_index),
void *data)
{
- EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params)
- {
- const MPoly *mp = &mr->mpoly[mlt->poly];
- if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
- lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v,
- mr->mloop[mlt->tri[1]].v,
- mr->mloop[mlt->tri[2]].v,
- mlt->tri[0],
- mlt->tri[1],
- mlt->tri[2],
- data);
- }
+ const MPoly *mp = &mr->mpoly[mlt->poly];
+ if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
+ lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v,
+ mr->mloop[mlt->tri[1]].v,
+ mr->mloop[mlt->tri[2]].v,
+ mlt->tri[0],
+ mlt->tri[1],
+ mlt->tri[2],
+ data);
}
- EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
}
static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *cache,
- void *ibo,
+ void *buf,
void *_data)
{
+ GPUIndexBuf *ibo = buf;
MeshExtract_LineAdjacency_Data *data = _data;
/* Create edges for remaining non manifold edges. */
EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh);
@@ -1559,14 +847,14 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
#undef NO_EDGE
-static const MeshExtract extract_lines_adjacency = {
+const MeshExtract extract_lines_adjacency = {
.init = extract_lines_adjacency_init,
.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm,
.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh,
.finish = extract_lines_adjacency_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_adjacency)};
/** \} */
@@ -1598,56 +886,51 @@ BLI_INLINE void edituv_tri_add(
}
static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
- const struct ExtractTriBMesh_Params *params,
+ BMLoop **elt,
+ const int UNUSED(elt_index),
void *data)
{
- EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params)
- {
- edituv_tri_add(data,
- BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN),
- BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT),
- BM_elem_index_get(elt[0]),
- BM_elem_index_get(elt[1]),
- BM_elem_index_get(elt[2]));
- }
- EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
+ edituv_tri_add(data,
+ BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT),
+ BM_elem_index_get(elt[0]),
+ BM_elem_index_get(elt[1]),
+ BM_elem_index_get(elt[2]));
}
static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr,
- const struct ExtractTriMesh_Params *params,
+ const MLoopTri *mlt,
+ const int UNUSED(elt_index),
void *data)
{
- EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params)
- {
- const MPoly *mp = &mr->mpoly[mlt->poly];
- edituv_tri_add(data,
- (mp->flag & ME_HIDE) != 0,
- (mp->flag & ME_FACE_SEL) != 0,
- mlt->tri[0],
- mlt->tri[1],
- mlt->tri[2]);
- }
- EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
+ const MPoly *mp = &mr->mpoly[mlt->poly];
+ edituv_tri_add(data,
+ (mp->flag & ME_HIDE) != 0,
+ (mp->flag & ME_FACE_SEL) != 0,
+ mlt->tri[0],
+ mlt->tri[1],
+ mlt->tri[2]);
}
static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *ibo,
+ void *buf,
void *data)
{
+ GPUIndexBuf *ibo = buf;
MeshExtract_EditUvElem_Data *extract_data = data;
GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
MEM_freeN(extract_data);
}
-static const MeshExtract extract_edituv_tris = {
+const MeshExtract extract_edituv_tris = {
.init = extract_edituv_tris_init,
.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm,
.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh,
.finish = extract_edituv_tris_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_tris)};
/** \} */
@@ -1674,27 +957,34 @@ BLI_INLINE void edituv_edge_add(
}
}
-static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr)
- {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+
edituv_edge_add(data,
- BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN),
- BM_elem_flag_test(loop->f, BM_ELEM_SELECT),
+ BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test_bool(f, BM_ELEM_SELECT),
l_index,
- BM_elem_index_get(loop->next));
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop);
+ BM_elem_index_get(l_iter->next));
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+
const int ml_index_last = mp->totloop + mp->loopstart - 1;
const int ml_index_next = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[ml->e] != ORIGINDEX_NONE);
@@ -1704,27 +994,27 @@ static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr,
ml_index,
ml_index_next);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *ibo,
+ void *buf,
void *data)
{
+ GPUIndexBuf *ibo = buf;
MeshExtract_EditUvElem_Data *extract_data = data;
GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
MEM_freeN(extract_data);
}
-static const MeshExtract extract_edituv_lines = {
+const MeshExtract extract_edituv_lines = {
.init = extract_edituv_lines_init,
.iter_poly_bm = extract_edituv_lines_iter_poly_bm,
.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh,
.finish = extract_edituv_lines_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_lines)};
/** \} */
@@ -1753,52 +1043,57 @@ BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data,
}
}
-static void extract_edituv_points_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_edituv_points_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- edituv_point_add(data,
- BM_elem_flag_test(l->f, BM_ELEM_HIDDEN),
- BM_elem_flag_test(l->f, BM_ELEM_SELECT),
- l_index);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+
+ edituv_point_add(
+ data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), l_index);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+
const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
mr->v_origindex[ml->v] != ORIGINDEX_NONE);
edituv_point_add(
data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *ibo,
+ void *buf,
void *data)
{
+ GPUIndexBuf *ibo = buf;
MeshExtract_EditUvElem_Data *extract_data = data;
GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
MEM_freeN(extract_data);
}
-static const MeshExtract extract_edituv_points = {
+const MeshExtract extract_edituv_points = {
.init = extract_edituv_points_init,
.iter_poly_bm = extract_edituv_points_iter_poly_bm,
.iter_poly_mesh = extract_edituv_points_iter_poly_mesh,
.finish = extract_edituv_points_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_points)};
/** \} */
@@ -1830,26 +1125,29 @@ BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data,
}
}
-static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int f_index,
void *data)
{
- EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
- {
- edituv_facedot_add(
- data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), f_index);
- }
- EXTRACT_POLY_FOREACH_BM_END;
+ edituv_facedot_add(data,
+ BM_elem_flag_test_bool(f, BM_ELEM_HIDDEN),
+ BM_elem_flag_test_bool(f, BM_ELEM_SELECT),
+ f_index);
}
static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *data)
{
if (mr->use_subsurf_fdots) {
/* Check #ME_VERT_FACEDOT. */
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+
const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
mr->p_origindex[mp_index] != ORIGINDEX_NONE);
const bool subd_fdot = (!mr->use_subsurf_fdots ||
@@ -1859,40 +1157,34 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
(mp->flag & ME_FACE_SEL) != 0,
mp_index);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
else {
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
- mr->p_origindex[mp_index] != ORIGINDEX_NONE);
- edituv_facedot_add(data,
- ((mp->flag & ME_HIDE) != 0) || !real_fdot,
- (mp->flag & ME_FACE_SEL) != 0,
- mp_index);
- }
- EXTRACT_POLY_FOREACH_MESH_END;
+ const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
+ mr->p_origindex[mp_index] != ORIGINDEX_NONE);
+ edituv_facedot_add(
+ data, ((mp->flag & ME_HIDE) != 0) || !real_fdot, (mp->flag & ME_FACE_SEL) != 0, mp_index);
}
}
static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *ibo,
+ void *buf,
void *_data)
{
+ GPUIndexBuf *ibo = buf;
MeshExtract_EditUvElem_Data *data = _data;
GPU_indexbuf_build_in_place(&data->elb, ibo);
MEM_freeN(data);
}
-static const MeshExtract extract_edituv_fdots = {
+const MeshExtract extract_edituv_fdots = {
.init = extract_edituv_fdots_init,
.iter_poly_bm = extract_edituv_fdots_iter_poly_bm,
.iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh,
.finish = extract_edituv_fdots_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_fdots)};
/** \} */
@@ -1914,6 +1206,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING Adjust #PosNorLoop struct accordingly. */
@@ -1921,7 +1214,6 @@ static void *extract_pos_nor_init(const MeshRenderData *mr,
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "vnor");
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
@@ -1949,28 +1241,34 @@ static void *extract_pos_nor_init(const MeshRenderData *mr,
}
static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
MeshExtract_PosNor_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
PosNorLoop *vert = &data->vbo_data[l_index];
- copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v));
- vert->nor = data->normals[BM_elem_index_get(l->v)].low;
- BMFace *efa = l->f;
- vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v));
+ vert->nor = data->normals[BM_elem_index_get(l_iter->v)].low;
+ vert->nor.w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *_data)
{
MeshExtract_PosNor_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+
PosNorLoop *vert = &data->vbo_data[ml_index];
const MVert *mv = &mr->mvert[ml->v];
copy_v3_v3(vert->pos, mv->co);
@@ -1988,96 +1286,86 @@ static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr,
vert->nor.w = 0;
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
+ BMEdge *eed,
+ const int ledge_index,
void *_data)
{
MeshExtract_PosNor_Data *data = _data;
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- int l_index = mr->loop_len + ledge_index * 2;
- PosNorLoop *vert = &data->vbo_data[l_index];
- copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
- copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
- vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low;
- vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low;
- }
- EXTRACT_LEDGE_FOREACH_BM_END;
+
+ int l_index = mr->loop_len + ledge_index * 2;
+ PosNorLoop *vert = &data->vbo_data[l_index];
+ copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
+ copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
+ vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low;
+ vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low;
}
static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
+ const MEdge *med,
+ const uint ledge_index,
void *_data)
{
MeshExtract_PosNor_Data *data = _data;
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- const int ml_index = mr->loop_len + ledge_index * 2;
- PosNorLoop *vert = &data->vbo_data[ml_index];
- copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
- copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
- vert[0].nor = data->normals[med->v1].low;
- vert[1].nor = data->normals[med->v2].low;
- }
- EXTRACT_LEDGE_FOREACH_MESH_END;
+ const int ml_index = mr->loop_len + ledge_index * 2;
+ PosNorLoop *vert = &data->vbo_data[ml_index];
+ copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
+ copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
+ vert[0].nor = data->normals[med->v1].low;
+ vert[1].nor = data->normals[med->v2].low;
}
static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr,
- const ExtractLVertBMesh_Params *params,
+ BMVert *eve,
+ const int lvert_index,
void *_data)
{
MeshExtract_PosNor_Data *data = _data;
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
- {
- const int l_index = offset + lvert_index;
- PosNorLoop *vert = &data->vbo_data[l_index];
- copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
- vert->nor = data->normals[BM_elem_index_get(eve)].low;
- }
- EXTRACT_LVERT_FOREACH_BM_END;
+
+ const int l_index = offset + lvert_index;
+ PosNorLoop *vert = &data->vbo_data[l_index];
+ copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
+ vert->nor = data->normals[BM_elem_index_get(eve)].low;
}
static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr,
- const ExtractLVertMesh_Params *params,
+ const MVert *mv,
+ const int lvert_index,
void *_data)
{
MeshExtract_PosNor_Data *data = _data;
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
- {
- const int ml_index = offset + lvert_index;
- const int v_index = mr->lverts[lvert_index];
- PosNorLoop *vert = &data->vbo_data[ml_index];
- copy_v3_v3(vert->pos, mv->co);
- vert->nor = data->normals[v_index].low;
- }
- EXTRACT_LVERT_FOREACH_MESH_END;
+
+ const int ml_index = offset + lvert_index;
+ const int v_index = mr->lverts[lvert_index];
+ PosNorLoop *vert = &data->vbo_data[ml_index];
+ copy_v3_v3(vert->pos, mv->co);
+ vert->nor = data->normals[v_index].low;
}
static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(vbo),
+ void *UNUSED(buf),
void *data)
{
MEM_freeN(data);
}
-static const MeshExtract extract_pos_nor = {
- .init = extract_pos_nor_init,
- .iter_poly_bm = extract_pos_nor_iter_poly_bm,
- .iter_poly_mesh = extract_pos_nor_iter_poly_mesh,
- .iter_ledge_bm = extract_pos_nor_iter_ledge_bm,
- .iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh,
- .iter_lvert_bm = extract_pos_nor_iter_lvert_bm,
- .iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh,
- .finish = extract_pos_nor_finish,
- .data_flag = 0,
- .use_threading = true,
-};
+const MeshExtract extract_pos_nor = {.init = extract_pos_nor_init,
+ .iter_poly_bm = extract_pos_nor_iter_poly_bm,
+ .iter_poly_mesh = extract_pos_nor_iter_poly_mesh,
+ .iter_ledge_bm = extract_pos_nor_iter_ledge_bm,
+ .iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh,
+ .iter_lvert_bm = extract_pos_nor_iter_lvert_bm,
+ .iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh,
+ .finish = extract_pos_nor_finish,
+ .data_type = 0,
+ .use_threading = true,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor)};
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -2098,6 +1386,7 @@ static void *extract_pos_nor_hq_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING Adjust #PosNorHQLoop struct accordingly. */
@@ -2105,7 +1394,6 @@ static void *extract_pos_nor_hq_init(const MeshRenderData *mr,
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "vnor");
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
@@ -2133,29 +1421,35 @@ static void *extract_pos_nor_hq_init(const MeshRenderData *mr,
}
static void extract_pos_nor_hq_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
MeshExtract_PosNorHQ_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
PosNorHQLoop *vert = &data->vbo_data[l_index];
- copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v));
- copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l->v)].high);
+ copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v));
+ copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l_iter->v)].high);
- BMFace *efa = l->f;
+ BMFace *efa = l_iter->f;
vert->nor[3] = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *_data)
{
MeshExtract_PosNorHQ_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+
PosNorHQLoop *vert = &data->vbo_data[ml_index];
const MVert *mv = &mr->mvert[ml->v];
copy_v3_v3(vert->pos, mv->co);
@@ -2174,91 +1468,80 @@ static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr,
vert->nor[3] = 0;
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_pos_nor_hq_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
+ BMEdge *eed,
+ const int ledge_index,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = _data;
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- int l_index = mr->loop_len + ledge_index * 2;
- PosNorHQLoop *vert = &data->vbo_data[l_index];
- copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
- copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
- copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high);
- vert[0].nor[3] = 0;
- copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high);
- vert[1].nor[3] = 0;
- }
- EXTRACT_LEDGE_FOREACH_BM_END;
+ int l_index = mr->loop_len + ledge_index * 2;
+ PosNorHQLoop *vert = &data->vbo_data[l_index];
+ copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
+ copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
+ copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high);
+ vert[0].nor[3] = 0;
+ copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high);
+ vert[1].nor[3] = 0;
}
static void extract_pos_nor_hq_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
+ const MEdge *med,
+ const uint ledge_index,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = _data;
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- const int ml_index = mr->loop_len + ledge_index * 2;
- PosNorHQLoop *vert = &data->vbo_data[ml_index];
- copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
- copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
- copy_v3_v3_short(vert[0].nor, data->normals[med->v1].high);
- vert[0].nor[3] = 0;
- copy_v3_v3_short(vert[1].nor, data->normals[med->v2].high);
- vert[1].nor[3] = 0;
- }
- EXTRACT_LEDGE_FOREACH_MESH_END;
+ const int ml_index = mr->loop_len + ledge_index * 2;
+ PosNorHQLoop *vert = &data->vbo_data[ml_index];
+ copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
+ copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
+ copy_v3_v3_short(vert[0].nor, data->normals[med->v1].high);
+ vert[0].nor[3] = 0;
+ copy_v3_v3_short(vert[1].nor, data->normals[med->v2].high);
+ vert[1].nor[3] = 0;
}
static void extract_pos_nor_hq_iter_lvert_bm(const MeshRenderData *mr,
- const ExtractLVertBMesh_Params *params,
+ BMVert *eve,
+ const int lvert_index,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = _data;
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
- {
- const int l_index = offset + lvert_index;
- PosNorHQLoop *vert = &data->vbo_data[l_index];
- copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
- copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high);
- vert->nor[3] = 0;
- }
- EXTRACT_LVERT_FOREACH_BM_END;
+
+ const int l_index = offset + lvert_index;
+ PosNorHQLoop *vert = &data->vbo_data[l_index];
+ copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
+ copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high);
+ vert->nor[3] = 0;
}
static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr,
- const ExtractLVertMesh_Params *params,
+ const MVert *mv,
+ const int lvert_index,
void *_data)
{
MeshExtract_PosNorHQ_Data *data = _data;
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
- {
- const int ml_index = offset + lvert_index;
- const int v_index = mr->lverts[lvert_index];
- PosNorHQLoop *vert = &data->vbo_data[ml_index];
- copy_v3_v3(vert->pos, mv->co);
- copy_v3_v3_short(vert->nor, data->normals[v_index].high);
- vert->nor[3] = 0;
- }
- EXTRACT_LVERT_FOREACH_MESH_END;
+
+ const int ml_index = offset + lvert_index;
+ const int v_index = mr->lverts[lvert_index];
+ PosNorHQLoop *vert = &data->vbo_data[ml_index];
+ copy_v3_v3(vert->pos, mv->co);
+ copy_v3_v3_short(vert->nor, data->normals[v_index].high);
+ vert->nor[3] = 0;
}
static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr),
struct MeshBatchCache *UNUSED(cache),
- void *UNUSED(vbo),
+ void *UNUSED(buf),
void *data)
{
MEM_freeN(data);
}
-static const MeshExtract extract_pos_nor_hq = {
+const MeshExtract extract_pos_nor_hq = {
.init = extract_pos_nor_hq_init,
.iter_poly_bm = extract_pos_nor_hq_iter_poly_bm,
.iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh,
@@ -2267,9 +1550,9 @@ static const MeshExtract extract_pos_nor_hq = {
.iter_lvert_bm = extract_pos_nor_hq_iter_lvert_bm,
.iter_lvert_mesh = extract_pos_nor_hq_iter_lvert_mesh,
.finish = extract_pos_nor_hq_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor)};
/** \} */
/* ---------------------------------------------------------------------- */
@@ -2284,12 +1567,12 @@ static void *extract_lnor_hq_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "lnor");
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -2297,36 +1580,37 @@ static void *extract_lnor_hq_init(const MeshRenderData *mr,
}
static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *data)
{
- if (mr->loop_normals) {
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(_l, l_index, params, mr)
- {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+ if (mr->loop_normals) {
normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(_l);
- }
- else {
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l->v));
+ else {
+ if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
+ normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l_iter->v));
}
else {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, l->f));
+ normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, f));
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
- }
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
gpuHQNor *lnor_data = &((gpuHQNor *)data)[ml_index];
if (mr->loop_normals) {
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
@@ -2352,16 +1636,14 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
lnor_data->w = 0;
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
-static const MeshExtract extract_lnor_hq = {
- .init = extract_lnor_hq_init,
- .iter_poly_bm = extract_lnor_hq_iter_poly_bm,
- .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh,
- .data_flag = MR_DATA_LOOP_NOR,
- .use_threading = true,
-};
+const MeshExtract extract_lnor_hq = {.init = extract_lnor_hq_init,
+ .iter_poly_bm = extract_lnor_hq_iter_poly_bm,
+ .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh,
+ .data_type = MR_DATA_LOOP_NOR,
+ .use_threading = true,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor)};
/** \} */
/* ---------------------------------------------------------------------- */
@@ -2372,12 +1654,12 @@ static void *extract_lnor_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "lnor");
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -2385,40 +1667,39 @@ static void *extract_lnor_init(const MeshRenderData *mr,
}
static void extract_lnor_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *data)
{
- if (mr->loop_normals) {
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+ if (mr->loop_normals) {
((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]);
- BMFace *efa = l->f;
- ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
}
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
- }
- else {
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) {
- ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, l->v));
+ else {
+ if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
+ ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(
+ bm_vert_no_get(mr, l_iter->v));
}
else {
- ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, l->f));
+ ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f));
}
- BMFace *efa = l->f;
- ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
}
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
- }
+ ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0;
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[ml_index];
if (mr->loop_normals) {
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
@@ -2444,16 +1725,14 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
lnor_data->w = 0;
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
-static const MeshExtract extract_lnor = {
- .init = extract_lnor_init,
- .iter_poly_bm = extract_lnor_iter_poly_bm,
- .iter_poly_mesh = extract_lnor_iter_poly_mesh,
- .data_flag = MR_DATA_LOOP_NOR,
- .use_threading = true,
-};
+const MeshExtract extract_lnor = {.init = extract_lnor_init,
+ .iter_poly_bm = extract_lnor_iter_poly_bm,
+ .iter_poly_mesh = extract_lnor_iter_poly_mesh,
+ .data_type = MR_DATA_LOOP_NOR,
+ .use_threading = true,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor)};
/** \} */
@@ -2463,6 +1742,7 @@ static const MeshExtract extract_lnor = {
static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
{
+ GPUVertBuf *vbo = buf;
GPUVertFormat format = {0};
GPU_vertformat_deinterleave(&format);
@@ -2512,7 +1792,6 @@ static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *ca
v_len = 1;
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, v_len);
@@ -2545,11 +1824,10 @@ static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *ca
return NULL;
}
-static const MeshExtract extract_uv = {
- .init = extract_uv_init,
- .data_flag = 0,
- .use_threading = false,
-};
+const MeshExtract extract_uv = {.init = extract_uv_init,
+ .data_type = 0,
+ .use_threading = false,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.uv)};
/** \} */
@@ -2557,10 +1835,10 @@ static const MeshExtract extract_uv = {
/** \name Extract Tangent layers
* \{ */
-static void extract_tan_ex(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- GPUVertBuf *vbo,
- const bool do_hq)
+static void extract_tan_ex_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ GPUVertBuf *vbo,
+ const bool do_hq)
{
GPUVertCompType comp_type = do_hq ? GPU_COMP_I16 : GPU_COMP_I10;
GPUVertFetchMode fetch_mode = GPU_FETCH_INT_TO_FLOAT_UNIT;
@@ -2731,15 +2009,15 @@ static void extract_tan_ex(const MeshRenderData *mr,
static void *extract_tan_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
{
- extract_tan_ex(mr, cache, buf, false);
+ extract_tan_ex_init(mr, cache, buf, false);
return NULL;
}
-static const MeshExtract extract_tan = {
- .init = extract_tan_init,
- .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
- .use_threading = false,
-};
+const MeshExtract extract_tan = {.init = extract_tan_init,
+ .data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR |
+ MR_DATA_LOOPTRI,
+ .use_threading = false,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan)};
/** \} */
@@ -2749,13 +2027,13 @@ static const MeshExtract extract_tan = {
static void *extract_tan_hq_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
{
- extract_tan_ex(mr, cache, buf, true);
+ extract_tan_ex_init(mr, cache, buf, true);
return NULL;
}
-static const MeshExtract extract_tan_hq = {
+const MeshExtract extract_tan_hq = {
.init = extract_tan_hq_init,
- .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
+ .data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
.use_threading = false,
};
@@ -2769,6 +2047,7 @@ static void *extract_sculpt_data_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
GPUVertFormat format = {0};
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
@@ -2783,7 +2062,6 @@ static void *extract_sculpt_data_init(const MeshRenderData *mr,
GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -2852,12 +2130,12 @@ static void *extract_sculpt_data_init(const MeshRenderData *mr,
return NULL;
}
-static const MeshExtract extract_sculpt_data = {
+const MeshExtract extract_sculpt_data = {
.init = extract_sculpt_data_init,
- .data_flag = 0,
+ .data_type = 0,
/* TODO: enable threading. */
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.sculpt_data)};
/** \} */
@@ -2867,6 +2145,7 @@ static const MeshExtract extract_sculpt_data = {
static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
{
+ GPUVertBuf *vbo = buf;
GPUVertFormat format = {0};
GPU_vertformat_deinterleave(&format);
@@ -2928,7 +2207,6 @@ static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *
}
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -3001,11 +2279,10 @@ static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *
return NULL;
}
-static const MeshExtract extract_vcol = {
- .init = extract_vcol_init,
- .data_flag = 0,
- .use_threading = false,
-};
+const MeshExtract extract_vcol = {.init = extract_vcol_init,
+ .data_type = 0,
+ .use_threading = false,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vcol)};
/** \} */
@@ -3022,6 +2299,7 @@ static void *extract_orco_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
@@ -3031,7 +2309,6 @@ static void *extract_orco_init(const MeshRenderData *mr,
GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -3045,32 +2322,36 @@ static void *extract_orco_init(const MeshRenderData *mr,
return data;
}
-static void extract_orco_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_orco_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *data)
{
MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr)
- {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
float *loop_orco = orco_data->vbo_data[l_index];
- copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]);
+ copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(l_iter->v)]);
loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_orco_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
float *loop_orco = orco_data->vbo_data[ml_index];
copy_v3_v3(loop_orco, orco_data->orco[ml->v]);
loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_orco_finish(const MeshRenderData *UNUSED(mr),
@@ -3081,14 +2362,13 @@ static void extract_orco_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data);
}
-static const MeshExtract extract_orco = {
- .init = extract_orco_init,
- .iter_poly_bm = extract_orco_iter_poly_bm,
- .iter_poly_mesh = extract_orco_iter_poly_mesh,
- .finish = extract_orco_finish,
- .data_flag = 0,
- .use_threading = true,
-};
+const MeshExtract extract_orco = {.init = extract_orco_init,
+ .iter_poly_bm = extract_orco_iter_poly_bm,
+ .iter_poly_mesh = extract_orco_iter_poly_mesh,
+ .finish = extract_orco_finish,
+ .data_type = 0,
+ .use_threading = true,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.orco)};
/** \} */
@@ -3124,11 +2404,12 @@ static void *extract_edge_fac_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
- GPUVertBuf *vbo = buf;
+
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
@@ -3159,43 +2440,47 @@ static void *extract_edge_fac_init(const MeshRenderData *mr,
}
static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
MeshExtract_EdgeFac_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- if (BM_edge_is_manifold(l->e)) {
- float ratio = loop_edge_factor_get(bm_face_no_get(mr, l->f),
- bm_vert_co_get(mr, l->v),
- bm_vert_no_get(mr, l->v),
- bm_vert_co_get(mr, l->next->v));
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+
+ if (BM_edge_is_manifold(l_iter->e)) {
+ float ratio = loop_edge_factor_get(bm_face_no_get(mr, f),
+ bm_vert_co_get(mr, l_iter->v),
+ bm_vert_no_get(mr, l_iter->v),
+ bm_vert_co_get(mr, l_iter->next->v));
data->vbo_data[l_index] = ratio * 253 + 1;
}
else {
data->vbo_data[l_index] = 255;
}
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *_data)
{
MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
- if (data->use_edge_render) {
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+
+ if (data->use_edge_render) {
const MEdge *med = &mr->medge[ml->e];
data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0;
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
- }
- else {
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ else {
+
/* Count loop per edge to detect non-manifold. */
if (data->edge_loop_count[ml->e] < 3) {
data->edge_loop_count[ml->e]++;
@@ -3217,34 +2502,28 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
data->vbo_data[ml_index] = 255;
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
}
static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
+ BMEdge *UNUSED(eed),
+ const int ledge_index,
void *_data)
{
MeshExtract_EdgeFac_Data *data = _data;
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255;
- data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255;
- }
- EXTRACT_LEDGE_FOREACH_BM_END;
+ data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255;
+ data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255;
}
static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
+ const MEdge *UNUSED(med),
+ const uint ledge_index,
void *_data)
{
MeshExtract_EdgeFac_Data *data = _data;
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255;
- data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255;
- }
- EXTRACT_LEDGE_FOREACH_MESH_END;
+
+ data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255;
+ data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255;
}
static void extract_edge_fac_finish(const MeshRenderData *mr,
@@ -3252,10 +2531,10 @@ static void extract_edge_fac_finish(const MeshRenderData *mr,
void *buf,
void *_data)
{
+ GPUVertBuf *vbo = buf;
MeshExtract_EdgeFac_Data *data = _data;
if (GPU_crappy_amd_driver()) {
- GPUVertBuf *vbo = (GPUVertBuf *)buf;
/* Some AMD drivers strangely crash with VBO's with a one byte format.
* To workaround we reinitialize the VBO with another format and convert
* all bytes to floats. */
@@ -3281,16 +2560,16 @@ static void extract_edge_fac_finish(const MeshRenderData *mr,
MEM_freeN(data);
}
-static const MeshExtract extract_edge_fac = {
+const MeshExtract extract_edge_fac = {
.init = extract_edge_fac_init,
.iter_poly_bm = extract_edge_fac_iter_poly_bm,
.iter_poly_mesh = extract_edge_fac_iter_poly_mesh,
.iter_ledge_bm = extract_edge_fac_iter_ledge_bm,
.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh,
.finish = extract_edge_fac_finish,
- .data_flag = MR_DATA_POLY_NOR,
+ .data_type = MR_DATA_POLY_NOR,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_fac)};
/** \} */
/* ---------------------------------------------------------------------- */
@@ -3361,11 +2640,11 @@ static void *extract_weights_init(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
@@ -3389,48 +2668,44 @@ static void *extract_weights_init(const MeshRenderData *mr,
return data;
}
-static void extract_weights_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_weights_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
MeshExtract_Weight_Data *data = _data;
- if (data->cd_ofs != -1) {
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l->v, data->cd_ofs);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+ if (data->cd_ofs != -1) {
+ const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l_iter->v, data->cd_ofs);
data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
- }
- else {
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
+ else {
data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
- }
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *_data)
{
MeshExtract_Weight_Data *data = _data;
- if (data->dvert != NULL) {
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+ if (data->dvert != NULL) {
const MDeformVert *dvert = &data->dvert[ml->v];
data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
- }
- else {
- const MDeformVert *dvert = NULL;
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ else {
+ const MDeformVert *dvert = NULL;
data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
}
@@ -3442,14 +2717,13 @@ static void extract_weights_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data);
}
-static const MeshExtract extract_weights = {
- .init = extract_weights_init,
- .iter_poly_bm = extract_weights_iter_poly_bm,
- .iter_poly_mesh = extract_weights_iter_poly_mesh,
- .finish = extract_weights_finish,
- .data_flag = 0,
- .use_threading = true,
-};
+const MeshExtract extract_weights = {.init = extract_weights_init,
+ .iter_poly_bm = extract_weights_iter_poly_bm,
+ .iter_poly_mesh = extract_weights_iter_poly_mesh,
+ .finish = extract_weights_finish,
+ .data_type = 0,
+ .use_threading = true,
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.weights)};
/** \} */
@@ -3599,40 +2873,45 @@ static void *extract_edit_data_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING: Adjust #EditLoopData struct accordingly. */
GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
GPU_vertformat_alias_add(&format, "flag");
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
return GPU_vertbuf_get_data(vbo);
}
static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
EditLoopData *data = (EditLoopData *)_data + l_index;
memset(data, 0x0, sizeof(*data));
- mesh_render_data_face_flag(mr, l->f, -1, data);
- mesh_render_data_edge_flag(mr, l->e, data);
- mesh_render_data_vert_flag(mr, l->v, data);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ mesh_render_data_face_flag(mr, f, -1, data);
+ mesh_render_data_edge_flag(mr, l_iter->e, data);
+ mesh_render_data_vert_flag(mr, l_iter->v, data);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *_data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
EditLoopData *data = (EditLoopData *)_data + ml_index;
memset(data, 0x0, sizeof(*data));
BMFace *efa = bm_original_face_get(mr, mp_index);
@@ -3648,84 +2927,72 @@ static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr,
mesh_render_data_vert_flag(mr, eve, data);
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
+ BMEdge *eed,
+ const int ledge_index,
void *_data)
{
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2);
- memset(data, 0x0, sizeof(*data) * 2);
- mesh_render_data_edge_flag(mr, eed, &data[0]);
- data[1] = data[0];
- mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
- mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
- }
- EXTRACT_LEDGE_FOREACH_BM_END;
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2);
+ memset(data, 0x0, sizeof(*data) * 2);
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
+ mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
}
static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
+ const MEdge *med,
+ const uint ledge_index,
void *_data)
{
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2;
- memset(data, 0x0, sizeof(*data) * 2);
- const int e_index = mr->ledges[ledge_index];
- BMEdge *eed = bm_original_edge_get(mr, e_index);
- BMVert *eve1 = bm_original_vert_get(mr, med->v1);
- BMVert *eve2 = bm_original_vert_get(mr, med->v2);
- if (eed) {
- mesh_render_data_edge_flag(mr, eed, &data[0]);
- data[1] = data[0];
- }
- if (eve1) {
- mesh_render_data_vert_flag(mr, eve1, &data[0]);
- }
- if (eve2) {
- mesh_render_data_vert_flag(mr, eve2, &data[1]);
- }
+ EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2;
+ memset(data, 0x0, sizeof(*data) * 2);
+ const int e_index = mr->ledges[ledge_index];
+ BMEdge *eed = bm_original_edge_get(mr, e_index);
+ BMVert *eve1 = bm_original_vert_get(mr, med->v1);
+ BMVert *eve2 = bm_original_vert_get(mr, med->v2);
+ if (eed) {
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ }
+ if (eve1) {
+ mesh_render_data_vert_flag(mr, eve1, &data[0]);
+ }
+ if (eve2) {
+ mesh_render_data_vert_flag(mr, eve2, &data[1]);
}
- EXTRACT_LEDGE_FOREACH_MESH_END;
}
static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr,
- const ExtractLVertBMesh_Params *params,
+ BMVert *eve,
+ const int lvert_index,
void *_data)
{
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
- {
- EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
- memset(data, 0x0, sizeof(*data));
- mesh_render_data_vert_flag(mr, eve, data);
- }
- EXTRACT_LVERT_FOREACH_BM_END;
+ EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
+ memset(data, 0x0, sizeof(*data));
+ mesh_render_data_vert_flag(mr, eve, data);
}
static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
- const ExtractLVertMesh_Params *params,
+ const MVert *UNUSED(mv),
+ const int lvert_index,
void *_data)
{
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
- {
- EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
- memset(data, 0x0, sizeof(*data));
- const int v_index = mr->lverts[lvert_index];
- BMVert *eve = bm_original_vert_get(mr, v_index);
- if (eve) {
- mesh_render_data_vert_flag(mr, eve, data);
- }
+
+ EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
+ memset(data, 0x0, sizeof(*data));
+ const int v_index = mr->lverts[lvert_index];
+ BMVert *eve = bm_original_vert_get(mr, v_index);
+ if (eve) {
+ mesh_render_data_vert_flag(mr, eve, data);
}
- EXTRACT_LVERT_FOREACH_MESH_END;
}
-static const MeshExtract extract_edit_data = {
+const MeshExtract extract_edit_data = {
.init = extract_edit_data_init,
.iter_poly_bm = extract_edit_data_iter_poly_bm,
.iter_poly_mesh = extract_edit_data_iter_poly_mesh,
@@ -3733,9 +3000,9 @@ static const MeshExtract extract_edit_data = {
.iter_ledge_mesh = extract_edit_data_iter_ledge_mesh,
.iter_lvert_bm = extract_edit_data_iter_lvert_bm,
.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edit_data)};
/** \} */
@@ -3752,6 +3019,7 @@ static void *extract_edituv_data_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING: Adjust #EditLoopData struct accordingly. */
@@ -3759,7 +3027,6 @@ static void *extract_edituv_data_init(const MeshRenderData *mr,
GPU_vertformat_alias_add(&format, "flag");
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -3772,28 +3039,34 @@ static void *extract_edituv_data_init(const MeshRenderData *mr,
}
static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
MeshExtract_EditUVData_Data *data = _data;
EditLoopData *eldata = &data->vbo_data[l_index];
memset(eldata, 0x0, sizeof(*eldata));
- mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata);
- mesh_render_data_face_flag(mr, l->f, data->cd_ofs, eldata);
- mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ mesh_render_data_loop_flag(mr, l_iter, data->cd_ofs, eldata);
+ mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata);
+ mesh_render_data_loop_edge_flag(mr, l_iter, data->cd_ofs, eldata);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *_data)
{
MeshExtract_EditUVData_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+
EditLoopData *eldata = &data->vbo_data[ml_index];
memset(eldata, 0x0, sizeof(*eldata));
BMFace *efa = bm_original_face_get(mr, mp_index);
@@ -3823,7 +3096,6 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
}
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr),
@@ -3834,14 +3106,14 @@ static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data);
}
-static const MeshExtract extract_edituv_data = {
+const MeshExtract extract_edituv_data = {
.init = extract_edituv_data_init,
.iter_poly_bm = extract_edituv_data_iter_poly_bm,
.iter_poly_mesh = extract_edituv_data_iter_poly_mesh,
.finish = extract_edituv_data_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_data)};
/** \} */
@@ -3853,12 +3125,12 @@ static void *extract_edituv_stretch_area_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -3880,11 +3152,12 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t
return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
}
-static void mesh_edituv_stretch_area_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(data))
+static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(data))
{
+ GPUVertBuf *vbo = buf;
float tot_area = 0.0f, tot_uv_area = 0.0f;
float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__);
@@ -3926,7 +3199,6 @@ static void mesh_edituv_stretch_area_finish(const MeshRenderData *mr,
}
/* Copy face data for each loop. */
- GPUVertBuf *vbo = buf;
uint16_t *loop_stretch = (uint16_t *)GPU_vertbuf_get_data(vbo);
if (mr->extract_type == MR_EXTRACT_BMESH) {
@@ -3952,12 +3224,12 @@ static void mesh_edituv_stretch_area_finish(const MeshRenderData *mr,
MEM_freeN(area_ratio);
}
-static const MeshExtract extract_edituv_stretch_area = {
+const MeshExtract extract_edituv_stretch_area = {
.init = extract_edituv_stretch_area_init,
- .finish = mesh_edituv_stretch_area_finish,
- .data_flag = 0,
+ .finish = extract_edituv_stretch_area_finish,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_area)};
/** \} */
@@ -4023,6 +3295,7 @@ static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* Waning: adjust #UVStretchAngle struct accordingly. */
@@ -4030,7 +3303,6 @@ static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr,
GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -4049,21 +3321,24 @@ static void *extract_edituv_stretch_angle_init(const MeshRenderData *mr,
}
static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
MeshExtract_StretchAngle_Data *data = _data;
float(*auv)[2] = data->auv, *last_auv = data->last_auv;
float(*av)[3] = data->av, *last_av = data->last_av;
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+
const MLoopUV *luv, *luv_next;
- BMLoop *l_next = l->next;
- BMFace *efa = l->f;
- if (l == BM_FACE_FIRST_LOOP(efa)) {
+ BMLoop *l_next = l_iter->next;
+ if (l_iter == BM_FACE_FIRST_LOOP(f)) {
/* First loop in face. */
- BMLoop *l_tmp = l->prev;
- BMLoop *l_next_tmp = l;
+ BMLoop *l_tmp = l_iter->prev;
+ BMLoop *l_next_tmp = l_iter;
luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs);
luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs);
compute_normalize_edge_vectors(auv,
@@ -4076,7 +3351,7 @@ static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr,
copy_v2_v2(last_auv, auv[1]);
copy_v3_v3(last_av, av[1]);
}
- if (l_next == BM_FACE_FIRST_LOOP(efa)) {
+ if (l_next == BM_FACE_FIRST_LOOP(f)) {
/* Move previous edge. */
copy_v2_v2(auv[0], auv[1]);
copy_v3_v3(av[0], av[1]);
@@ -4085,27 +3360,31 @@ static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr,
copy_v3_v3(av[1], last_av);
}
else {
- luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs);
+ luv = BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs);
luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs);
- compute_normalize_edge_vectors(
- auv, av, luv->uv, luv_next->uv, bm_vert_co_get(mr, l->v), bm_vert_co_get(mr, l_next->v));
+ compute_normalize_edge_vectors(auv,
+ av,
+ luv->uv,
+ luv_next->uv,
+ bm_vert_co_get(mr, l_iter->v),
+ bm_vert_co_get(mr, l_next->v));
}
edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[l_index]);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *_data)
{
MeshExtract_StretchAngle_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
float(*auv)[2] = data->auv, *last_auv = data->last_auv;
float(*av)[3] = data->av, *last_av = data->last_av;
- int l_next = ml_index + 1, ml_index_end = mp->loopstart + mp->totloop;
+ int l_next = ml_index + 1;
const MVert *v, *v_next;
if (ml_index == mp->loopstart) {
/* First loop in face. */
@@ -4136,7 +3415,6 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr
}
edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[ml_index]);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_edituv_stretch_angle_finish(const MeshRenderData *UNUSED(mr),
@@ -4147,14 +3425,14 @@ static void extract_edituv_stretch_angle_finish(const MeshRenderData *UNUSED(mr)
MEM_freeN(data);
}
-static const MeshExtract extract_edituv_stretch_angle = {
+const MeshExtract extract_edituv_stretch_angle = {
.init = extract_edituv_stretch_angle_init,
.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm,
.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh,
.finish = extract_edituv_stretch_angle_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_angle)};
/** \} */
@@ -4166,12 +3444,12 @@ static void *extract_mesh_analysis_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -4725,14 +4003,14 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
MEM_freeN(vert_angles);
}
-static void extract_mesh_analysis_finish(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *UNUSED(data))
+static void extract_analysis_iter_finish_mesh(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
{
+ GPUVertBuf *vbo = buf;
BLI_assert(mr->edit_bmesh);
- GPUVertBuf *vbo = buf;
float *l_weight = (float *)GPU_vertbuf_get_data(vbo);
switch (mr->toolsettings->statvis.type) {
@@ -4754,14 +4032,14 @@ static void extract_mesh_analysis_finish(const MeshRenderData *mr,
}
}
-static const MeshExtract extract_mesh_analysis = {
+const MeshExtract extract_mesh_analysis = {
.init = extract_mesh_analysis_init,
- .finish = extract_mesh_analysis_finish,
+ .finish = extract_analysis_iter_finish_mesh,
/* This is not needed for all visualization types.
* * Maybe split into different extract. */
- .data_flag = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI,
+ .data_type = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.mesh_analysis)};
/** \} */
@@ -4773,79 +4051,75 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
- GPUVertBuf *vbo = buf;
+
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
return GPU_vertbuf_get_data(vbo);
}
static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int f_index,
void *data)
{
float(*center)[3] = data;
- EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
- {
- float *co = center[f_index];
- zero_v3(co);
+ float *co = center[f_index];
+ zero_v3(co);
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- add_v3_v3(co, bm_vert_co_get(mr, l_iter->v));
- } while ((l_iter = l_iter->next) != l_first);
- mul_v3_fl(co, 1.0f / (float)f->len);
- }
- EXTRACT_POLY_FOREACH_BM_END;
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ add_v3_v3(co, bm_vert_co_get(mr, l_iter->v));
+ } while ((l_iter = l_iter->next) != l_first);
+ mul_v3_fl(co, 1.0f / (float)f->len);
}
static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *data)
{
float(*center)[3] = (float(*)[3])data;
+ float *co = center[mp_index];
+ zero_v3(co);
+
const MVert *mvert = mr->mvert;
const MLoop *mloop = mr->mloop;
- if (mr->use_subsurf_fdots) {
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+ if (mr->use_subsurf_fdots) {
const MVert *mv = &mr->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
copy_v3_v3(center[mp_index], mv->co);
+ break;
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
- }
- else {
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- float *co = center[mp_index];
- zero_v3(co);
-
- const MLoop *ml = &mloop[mp->loopstart];
- for (int i = 0; i < mp->totloop; i++, ml++) {
- const MVert *mv = &mvert[ml->v];
- add_v3_v3(center[mp_index], mv->co);
- }
- mul_v3_fl(co, 1.0f / (float)mp->totloop);
+ else {
+ const MVert *mv = &mvert[ml->v];
+ add_v3_v3(center[mp_index], mv->co);
}
- EXTRACT_POLY_FOREACH_MESH_END;
+ }
+
+ if (!mr->use_subsurf_fdots) {
+ mul_v3_fl(co, 1.0f / (float)mp->totloop);
}
}
-static const MeshExtract extract_fdots_pos = {
+const MeshExtract extract_fdots_pos = {
.init = extract_fdots_pos_init,
.iter_poly_bm = extract_fdots_pos_iter_poly_bm,
.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_pos)};
/** \} */
@@ -4861,11 +4135,12 @@ static void *extract_fdots_nor_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
- GPUVertBuf *vbo = buf;
+
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
@@ -4877,8 +4152,8 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr,
void *buf,
void *UNUSED(data))
{
- static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
GPUVertBuf *vbo = buf;
+ static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
GPUPackedNormal *nor = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo);
BMFace *efa;
@@ -4921,12 +4196,12 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr,
}
}
-static const MeshExtract extract_fdots_nor = {
+const MeshExtract extract_fdots_nor = {
.init = extract_fdots_nor_init,
.finish = extract_fdots_nor_finish,
- .data_flag = MR_DATA_POLY_NOR,
+ .data_type = MR_DATA_POLY_NOR,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)};
/** \} */
@@ -4937,11 +4212,12 @@ static void *extract_fdots_nor_hq_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
- GPUVertBuf *vbo = buf;
+
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
@@ -4953,8 +4229,8 @@ static void extract_fdots_nor_hq_finish(const MeshRenderData *mr,
void *buf,
void *UNUSED(data))
{
- static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
GPUVertBuf *vbo = buf;
+ static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
short *nor = (short *)GPU_vertbuf_get_data(vbo);
BMFace *efa;
@@ -4997,12 +4273,12 @@ static void extract_fdots_nor_hq_finish(const MeshRenderData *mr,
}
}
-static const MeshExtract extract_fdots_nor_hq = {
+const MeshExtract extract_fdots_nor_hq = {
.init = extract_fdots_nor_hq_init,
.finish = extract_fdots_nor_hq_finish,
- .data_flag = MR_DATA_POLY_NOR,
+ .data_type = MR_DATA_POLY_NOR,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)};
/** \} */
@@ -5020,13 +4296,14 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "au");
GPU_vertformat_alias_add(&format, "pos");
}
- GPUVertBuf *vbo = buf;
+
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
@@ -5047,42 +4324,41 @@ static void *extract_fdots_uv_init(const MeshRenderData *mr,
return data;
}
-static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
MeshExtract_FdotUV_Data *data = _data;
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- float w = 1.0f / (float)l->f->len;
- const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs);
- madd_v2_v2fl(data->vbo_data[BM_elem_index_get(l->f)], luv->uv, w);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ float w = 1.0f / (float)f->len;
+ const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs);
+ madd_v2_v2fl(data->vbo_data[BM_elem_index_get(f)], luv->uv, w);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *_data)
{
MeshExtract_FdotUV_Data *data = _data;
- if (mr->use_subsurf_fdots) {
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
+ if (mr->use_subsurf_fdots) {
const MVert *mv = &mr->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
copy_v2_v2(data->vbo_data[mp_index], data->uv_data[ml_index].uv);
}
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
- }
- else {
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ else {
float w = 1.0f / (float)mp->totloop;
madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w);
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
}
@@ -5094,14 +4370,15 @@ static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data);
}
-static const MeshExtract extract_fdots_uv = {
+const MeshExtract extract_fdots_uv = {
.init = extract_fdots_uv_init,
.iter_poly_bm = extract_fdots_uv_iter_poly_bm,
.iter_poly_mesh = extract_fdots_uv_iter_poly_mesh,
.finish = extract_fdots_uv_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_uv)};
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -5117,11 +4394,12 @@ static void *extract_fdots_edituv_data_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U8, 4, GPU_FETCH_INT);
}
- GPUVertBuf *vbo = buf;
+
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
@@ -5132,34 +4410,28 @@ static void *extract_fdots_edituv_data_init(const MeshRenderData *mr,
}
static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+ BMFace *f,
+ const int UNUSED(f_index),
void *_data)
{
MeshExtract_EditUVFdotData_Data *data = _data;
- EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
- {
- EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)];
- memset(eldata, 0x0, sizeof(*eldata));
- mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata);
- }
- EXTRACT_POLY_FOREACH_BM_END;
+ EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)];
+ memset(eldata, 0x0, sizeof(*eldata));
+ mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata);
}
static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *UNUSED(mp),
+ const int mp_index,
void *_data)
{
MeshExtract_EditUVFdotData_Data *data = _data;
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- EditLoopData *eldata = &data->vbo_data[mp_index];
- memset(eldata, 0x0, sizeof(*eldata));
- BMFace *efa = bm_original_face_get(mr, mp_index);
- if (efa) {
- mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata);
- }
+ EditLoopData *eldata = &data->vbo_data[mp_index];
+ memset(eldata, 0x0, sizeof(*eldata));
+ BMFace *efa = bm_original_face_get(mr, mp_index);
+ if (efa) {
+ mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata);
}
- EXTRACT_POLY_FOREACH_MESH_END;
}
static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr),
@@ -5170,14 +4442,15 @@ static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data);
}
-static const MeshExtract extract_fdots_edituv_data = {
+const MeshExtract extract_fdots_edituv_data = {
.init = extract_fdots_edituv_data_init,
.iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm,
.iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh,
.finish = extract_fdots_edituv_data_finish,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_edituv_data)};
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -5193,6 +4466,7 @@ static void *extract_skin_roots_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
/* Exclusively for edit mode. */
BLI_assert(mr->bm);
@@ -5201,7 +4475,7 @@ static void *extract_skin_roots_init(const MeshRenderData *mr,
GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "local_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
- GPUVertBuf *vbo = buf;
+
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->bm->totvert);
@@ -5228,11 +4502,11 @@ static void *extract_skin_roots_init(const MeshRenderData *mr,
return NULL;
}
-static const MeshExtract extract_skin_roots = {
+const MeshExtract extract_skin_roots = {
.init = extract_skin_roots_init,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = false,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.skin_roots)};
/** \} */
@@ -5244,12 +4518,12 @@ static void *extract_select_idx_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* TODO rename "color" to something more descriptive. */
GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
}
- GPUVertBuf *vbo = buf;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
return GPU_vertbuf_get_data(vbo);
@@ -5260,169 +4534,163 @@ static void *extract_select_idx_init(const MeshRenderData *mr,
* index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the
* shader to output original index. */
-static void extract_poly_idx_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_poly_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int f_index,
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- ((uint32_t *)data)[l_index] = BM_elem_index_get(l->f);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+ ((uint32_t *)data)[l_index] = f_index;
+ } while ((l_iter = l_iter->next) != l_first);
}
-static void extract_edge_idx_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_edge_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- ((uint32_t *)data)[l_index] = BM_elem_index_get(l->e);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+ ((uint32_t *)data)[l_index] = BM_elem_index_get(l_iter->e);
+ } while ((l_iter = l_iter->next) != l_first);
}
-static void extract_vert_idx_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_vert_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *f,
+ const int UNUSED(f_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
- {
- ((uint32_t *)data)[l_index] = BM_elem_index_get(l->v);
- }
- EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ const int l_index = BM_elem_index_get(l_iter);
+ ((uint32_t *)data)[l_index] = BM_elem_index_get(l_iter->v);
+ } while ((l_iter = l_iter->next) != l_first);
}
static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
+ BMEdge *eed,
+ const int ledge_index,
void *data)
{
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed);
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed);
- }
- EXTRACT_LEDGE_FOREACH_BM_END;
+ ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed);
+ ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed);
}
static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr,
- const ExtractLEdgeBMesh_Params *params,
+ BMEdge *eed,
+ const int ledge_index,
void *data)
{
- EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
- {
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1);
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2);
- }
- EXTRACT_LEDGE_FOREACH_BM_END;
+ ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1);
+ ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2);
}
static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr,
- const ExtractLVertBMesh_Params *params,
+ BMVert *eve,
+ const int lvert_index,
void *data)
{
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
- {
- ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve);
- }
- EXTRACT_LVERT_FOREACH_BM_END;
+
+ ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve);
}
static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int mp_index,
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
((uint32_t *)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index;
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
((uint32_t *)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e;
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *mp,
+ const int UNUSED(mp_index),
void *data)
{
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
- {
+ const MLoop *mloop = mr->mloop;
+ const int ml_index_end = mp->loopstart + mp->totloop;
+ for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
+ const MLoop *ml = &mloop[ml_index];
((uint32_t *)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v;
}
- EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
}
static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
+ const MEdge *UNUSED(med),
+ const uint ledge_index,
void *data)
{
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- const int e_index = mr->ledges[ledge_index];
- const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index;
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig;
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig;
- }
- EXTRACT_LEDGE_FOREACH_MESH_END;
+ const int e_index = mr->ledges[ledge_index];
+ const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index;
+ ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig;
+ ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig;
}
static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr,
- const ExtractLEdgeMesh_Params *params,
+ const MEdge *med,
+ const uint ledge_index,
void *data)
{
- EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
- {
- int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1;
- int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2;
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig;
- ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig;
- }
- EXTRACT_LEDGE_FOREACH_MESH_END;
+ int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1;
+ int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2;
+ ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig;
+ ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig;
}
static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr,
- const ExtractLVertMesh_Params *params,
+ const MVert *UNUSED(mv),
+ const int lvert_index,
void *data)
{
const int offset = mr->loop_len + (mr->edge_loose_len * 2);
- EXTRACT_LVERT_FOREACH_MESH_BEGIN(med, lvert_index, params, mr)
- {
- const int v_index = mr->lverts[lvert_index];
- const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index;
- ((uint32_t *)data)[offset + lvert_index] = v_orig;
- }
- EXTRACT_LVERT_FOREACH_MESH_END;
+
+ const int v_index = mr->lverts[lvert_index];
+ const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index;
+ ((uint32_t *)data)[offset + lvert_index] = v_orig;
}
-static const MeshExtract extract_poly_idx = {
+const MeshExtract extract_poly_idx = {
.init = extract_select_idx_init,
.iter_poly_bm = extract_poly_idx_iter_poly_bm,
.iter_poly_mesh = extract_poly_idx_iter_poly_mesh,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.poly_idx)};
-static const MeshExtract extract_edge_idx = {
+const MeshExtract extract_edge_idx = {
.init = extract_select_idx_init,
.iter_poly_bm = extract_edge_idx_iter_poly_bm,
.iter_poly_mesh = extract_edge_idx_iter_poly_mesh,
.iter_ledge_bm = extract_edge_idx_iter_ledge_bm,
.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_idx)};
-static const MeshExtract extract_vert_idx = {
+const MeshExtract extract_vert_idx = {
.init = extract_select_idx_init,
.iter_poly_bm = extract_vert_idx_iter_poly_bm,
.iter_poly_mesh = extract_vert_idx_iter_poly_mesh,
@@ -5430,736 +4698,51 @@ static const MeshExtract extract_vert_idx = {
.iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh,
.iter_lvert_bm = extract_vert_idx_iter_lvert_bm,
.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vert_idx)};
-static void *extract_select_fdot_idx_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf)
+static void *extract_fdot_idx_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf)
{
+ GPUVertBuf *vbo = buf;
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* TODO rename "color" to something more descriptive. */
GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
}
- GPUVertBuf *vbo = buf;
+
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
return GPU_vertbuf_get_data(vbo);
}
-static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *mr,
- const ExtractPolyBMesh_Params *params,
+static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr),
+ BMFace *UNUSED(f),
+ const int f_index,
void *data)
{
- EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
- {
- ((uint32_t *)data)[f_index] = f_index;
- }
- EXTRACT_POLY_FOREACH_BM_END;
+ ((uint32_t *)data)[f_index] = f_index;
}
static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr,
- const ExtractPolyMesh_Params *params,
+ const MPoly *UNUSED(mp),
+ const int mp_index,
void *data)
{
if (mr->p_origindex != NULL) {
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index];
- }
- EXTRACT_POLY_FOREACH_MESH_END;
+ ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index];
}
else {
- EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
- {
- ((uint32_t *)data)[mp_index] = mp_index;
- }
- EXTRACT_POLY_FOREACH_MESH_END;
+ ((uint32_t *)data)[mp_index] = mp_index;
}
}
-static const MeshExtract extract_fdot_idx = {
- .init = extract_select_fdot_idx_init,
+const MeshExtract extract_fdot_idx = {
+ .init = extract_fdot_idx_init,
.iter_poly_bm = extract_fdot_idx_iter_poly_bm,
.iter_poly_mesh = extract_fdot_idx_iter_poly_mesh,
- .data_flag = 0,
+ .data_type = 0,
.use_threading = true,
-};
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name ExtractTaskData
- * \{ */
-typedef struct ExtractUserData {
- void *user_data;
-} ExtractUserData;
-
-typedef enum ExtractTaskDataType {
- EXTRACT_MESH_EXTRACT,
- EXTRACT_LINES_LOOSE,
-} ExtractTaskDataType;
-
-typedef struct ExtractTaskData {
- void *next, *prev;
- const MeshRenderData *mr;
- struct MeshBatchCache *cache;
- const MeshExtract *extract;
- ExtractTaskDataType tasktype;
- eMRIterType iter_type;
- int start, end;
- /** Decremented each time a task is finished. */
- int32_t *task_counter;
- void *buf;
- ExtractUserData *user_data;
-} ExtractTaskData;
-
-static ExtractTaskData *extract_task_data_create_mesh_extract(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- const MeshExtract *extract,
- void *buf,
- int32_t *task_counter)
-{
- ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), __func__);
- taskdata->next = NULL;
- taskdata->prev = NULL;
- taskdata->tasktype = EXTRACT_MESH_EXTRACT;
- taskdata->mr = mr;
- taskdata->cache = cache;
- taskdata->extract = extract;
- taskdata->buf = buf;
-
- /* #ExtractUserData is shared between the iterations as it holds counters to detect if the
- * extraction is finished. To make sure the duplication of the user_data does not create a new
- * instance of the counters we allocate the user_data in its own container.
- *
- * This structure makes sure that when extract_init is called, that the user data of all
- * iterations are updated. */
- taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__);
- taskdata->iter_type = mesh_extract_iter_type(extract);
- taskdata->task_counter = task_counter;
- taskdata->start = 0;
- taskdata->end = INT_MAX;
- return taskdata;
-}
-
-static ExtractTaskData *extract_task_data_create_lines_loose(const MeshRenderData *mr,
- struct MeshBatchCache *cache)
-{
- ExtractTaskData *taskdata = MEM_callocN(sizeof(*taskdata), __func__);
- taskdata->tasktype = EXTRACT_LINES_LOOSE;
- taskdata->mr = mr;
- taskdata->cache = cache;
- return taskdata;
-}
-
-static void extract_task_data_free(void *data)
-{
- ExtractTaskData *task_data = data;
- MEM_SAFE_FREE(task_data->user_data);
- MEM_freeN(task_data);
-}
-
-BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
- const eMRIterType iter_type,
- int start,
- int end,
- const MeshExtract *extract,
- void *user_data)
-{
- switch (mr->extract_type) {
- case MR_EXTRACT_BMESH:
- if (iter_type & MR_ITER_LOOPTRI) {
- extract->iter_looptri_bm(mr,
- &(const ExtractTriBMesh_Params){
- .looptris = mr->edit_bmesh->looptris,
- .tri_range = {start, min_ii(mr->tri_len, end)},
- },
- user_data);
- }
- if (iter_type & MR_ITER_POLY) {
- extract->iter_poly_bm(mr,
- &(const ExtractPolyBMesh_Params){
- .poly_range = {start, min_ii(mr->poly_len, end)},
- },
- user_data);
- }
- if (iter_type & MR_ITER_LEDGE) {
- extract->iter_ledge_bm(mr,
- &(const ExtractLEdgeBMesh_Params){
- .ledge = mr->ledges,
- .ledge_range = {start, min_ii(mr->edge_loose_len, end)},
- },
- user_data);
- }
- if (iter_type & MR_ITER_LVERT) {
- extract->iter_lvert_bm(mr,
- &(const ExtractLVertBMesh_Params){
- .lvert = mr->lverts,
- .lvert_range = {start, min_ii(mr->vert_loose_len, end)},
- },
- user_data);
- }
- break;
- case MR_EXTRACT_MAPPED:
- case MR_EXTRACT_MESH:
- if (iter_type & MR_ITER_LOOPTRI) {
- extract->iter_looptri_mesh(mr,
- &(const ExtractTriMesh_Params){
- .mlooptri = mr->mlooptri,
- .tri_range = {start, min_ii(mr->tri_len, end)},
- },
- user_data);
- }
- if (iter_type & MR_ITER_POLY) {
- extract->iter_poly_mesh(mr,
- &(const ExtractPolyMesh_Params){
- .poly_range = {start, min_ii(mr->poly_len, end)},
- },
- user_data);
- }
- if (iter_type & MR_ITER_LEDGE) {
- extract->iter_ledge_mesh(mr,
- &(const ExtractLEdgeMesh_Params){
- .ledge = mr->ledges,
- .ledge_range = {start, min_ii(mr->edge_loose_len, end)},
- },
- user_data);
- }
- if (iter_type & MR_ITER_LVERT) {
- extract->iter_lvert_mesh(mr,
- &(const ExtractLVertMesh_Params){
- .lvert = mr->lverts,
- .lvert_range = {start, min_ii(mr->vert_loose_len, end)},
- },
- user_data);
- }
- break;
- }
-}
-
-static void extract_init(ExtractTaskData *data)
-{
- if (data->tasktype == EXTRACT_MESH_EXTRACT) {
- data->user_data->user_data = data->extract->init(data->mr, data->cache, data->buf);
- }
-}
-
-static void extract_run(void *__restrict taskdata)
-{
- ExtractTaskData *data = (ExtractTaskData *)taskdata;
- if (data->tasktype == EXTRACT_MESH_EXTRACT) {
- mesh_extract_iter(data->mr,
- data->iter_type,
- data->start,
- data->end,
- data->extract,
- data->user_data->user_data);
-
- /* If this is the last task, we do the finish function. */
- int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
- if (remainin_tasks == 0 && data->extract->finish != NULL) {
- data->extract->finish(data->mr, data->cache, data->buf, data->user_data->user_data);
- }
- }
- else if (data->tasktype == EXTRACT_LINES_LOOSE) {
- extract_lines_loose_subbuffer(data->mr, data->cache);
- }
-}
-
-static void extract_init_and_run(void *__restrict taskdata)
-{
- extract_init((ExtractTaskData *)taskdata);
- extract_run(taskdata);
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Task Node - Update Mesh Render Data
- * \{ */
-typedef struct MeshRenderDataUpdateTaskData {
- MeshRenderData *mr;
- eMRIterType iter_type;
- eMRDataType data_flag;
-} MeshRenderDataUpdateTaskData;
-
-static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata)
-{
- BLI_assert(taskdata);
- MeshRenderData *mr = taskdata->mr;
- mesh_render_data_free(mr);
- MEM_freeN(taskdata);
-}
-
-static void mesh_extract_render_data_node_exec(void *__restrict task_data)
-{
- MeshRenderDataUpdateTaskData *update_task_data = task_data;
- MeshRenderData *mr = update_task_data->mr;
- const eMRIterType iter_type = update_task_data->iter_type;
- const eMRDataType data_flag = update_task_data->data_flag;
-
- mesh_render_data_update_normals(mr, iter_type, data_flag);
- mesh_render_data_update_looptris(mr, iter_type, data_flag);
-}
-
-static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph,
- MeshRenderData *mr,
- const eMRIterType iter_type,
- const eMRDataType data_flag)
-{
- MeshRenderDataUpdateTaskData *task_data = MEM_mallocN(sizeof(MeshRenderDataUpdateTaskData),
- __func__);
- task_data->mr = mr;
- task_data->iter_type = iter_type;
- task_data->data_flag = data_flag;
-
- struct TaskNode *task_node = BLI_task_graph_node_create(
- task_graph,
- mesh_extract_render_data_node_exec,
- task_data,
- (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free);
- return task_node;
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Task Node - Extract Single Threaded
- * \{ */
-typedef struct ExtractSingleThreadedTaskData {
- ListBase task_datas;
-} ExtractSingleThreadedTaskData;
-
-static void extract_single_threaded_task_data_free(ExtractSingleThreadedTaskData *taskdata)
-{
- BLI_assert(taskdata);
- LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) {
- extract_task_data_free(td);
- }
- BLI_listbase_clear(&taskdata->task_datas);
- MEM_freeN(taskdata);
-}
-
-static void extract_single_threaded_task_node_exec(void *__restrict task_data)
-{
- ExtractSingleThreadedTaskData *extract_task_data = task_data;
- LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) {
- extract_init_and_run(td);
- }
-}
-
-static struct TaskNode *extract_single_threaded_task_node_create(
- struct TaskGraph *task_graph, ExtractSingleThreadedTaskData *task_data)
-{
- struct TaskNode *task_node = BLI_task_graph_node_create(
- task_graph,
- extract_single_threaded_task_node_exec,
- task_data,
- (TaskGraphNodeFreeFunction)extract_single_threaded_task_data_free);
- return task_node;
-}
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Task Node - UserData Initializer
- * \{ */
-typedef struct UserDataInitTaskData {
- ListBase task_datas;
- int32_t *task_counters;
-
-} UserDataInitTaskData;
-
-static void user_data_init_task_data_free(UserDataInitTaskData *taskdata)
-{
- BLI_assert(taskdata);
- LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) {
- extract_task_data_free(td);
- }
- BLI_listbase_clear(&taskdata->task_datas);
- MEM_SAFE_FREE(taskdata->task_counters);
- MEM_freeN(taskdata);
-}
-
-static void user_data_init_task_data_exec(void *__restrict task_data)
-{
- UserDataInitTaskData *extract_task_data = task_data;
- LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) {
- extract_init(td);
- }
-}
-
-static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph,
- UserDataInitTaskData *task_data)
-{
- struct TaskNode *task_node = BLI_task_graph_node_create(
- task_graph,
- user_data_init_task_data_exec,
- task_data,
- (TaskGraphNodeFreeFunction)user_data_init_task_data_free);
- return task_node;
-}
-
-/** \} */
-/* ---------------------------------------------------------------------- */
-/** \name Extract Loop
- * \{ */
-
-static void extract_range_task_create(struct TaskGraph *task_graph,
- struct TaskNode *task_node_user_data_init,
- ExtractTaskData *taskdata,
- const eMRIterType type,
- int start,
- int length)
-{
- taskdata = MEM_dupallocN(taskdata);
- atomic_add_and_fetch_int32(taskdata->task_counter, 1);
- taskdata->iter_type = type;
- taskdata->start = start;
- taskdata->end = start + length;
- struct TaskNode *task_node = BLI_task_graph_node_create(
- task_graph, extract_run, taskdata, MEM_freeN);
- BLI_task_graph_edge_create(task_node_user_data_init, task_node);
-}
-
-static void extract_task_create(struct TaskGraph *task_graph,
- struct TaskNode *task_node_mesh_render_data,
- struct TaskNode *task_node_user_data_init,
- ListBase *single_threaded_task_datas,
- ListBase *user_data_init_task_datas,
- const Scene *scene,
- const MeshRenderData *mr,
- MeshBatchCache *cache,
- const MeshExtract *extract,
- void *buf,
- int32_t *task_counter)
-{
- BLI_assert(scene != NULL);
- const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
- GPU_use_hq_normals_workaround();
- if (do_hq_normals) {
- if (extract == &extract_lnor) {
- extract = &extract_lnor_hq;
- }
- else if (extract == &extract_pos_nor) {
- extract = &extract_pos_nor_hq;
- }
- else if (extract == &extract_tan) {
- extract = &extract_tan_hq;
- }
- else if (extract == &extract_fdots_nor) {
- extract = &extract_fdots_nor_hq;
- }
- }
-
- /* Divide extraction of the VBO/IBO into sensible chunks of works. */
- ExtractTaskData *taskdata = extract_task_data_create_mesh_extract(
- mr, cache, extract, buf, task_counter);
-
- /* Simple heuristic. */
- const int chunk_size = 8192;
- const bool use_thread = (mr->loop_len + mr->loop_loose_len) > chunk_size;
- if (use_thread && extract->use_threading) {
-
- /* Divide task into sensible chunks. */
- if (taskdata->iter_type & MR_ITER_LOOPTRI) {
- for (int i = 0; i < mr->tri_len; i += chunk_size) {
- extract_range_task_create(
- task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size);
- }
- }
- if (taskdata->iter_type & MR_ITER_POLY) {
- for (int i = 0; i < mr->poly_len; i += chunk_size) {
- extract_range_task_create(
- task_graph, task_node_user_data_init, taskdata, MR_ITER_POLY, i, chunk_size);
- }
- }
- if (taskdata->iter_type & MR_ITER_LEDGE) {
- for (int i = 0; i < mr->edge_loose_len; i += chunk_size) {
- extract_range_task_create(
- task_graph, task_node_user_data_init, taskdata, MR_ITER_LEDGE, i, chunk_size);
- }
- }
- if (taskdata->iter_type & MR_ITER_LVERT) {
- for (int i = 0; i < mr->vert_loose_len; i += chunk_size) {
- extract_range_task_create(
- task_graph, task_node_user_data_init, taskdata, MR_ITER_LVERT, i, chunk_size);
- }
- }
- BLI_addtail(user_data_init_task_datas, taskdata);
- }
- else if (use_thread) {
- /* One task for the whole VBO. */
- (*task_counter)++;
- struct TaskNode *one_task = BLI_task_graph_node_create(
- task_graph, extract_init_and_run, taskdata, extract_task_data_free);
- BLI_task_graph_edge_create(task_node_mesh_render_data, one_task);
- }
- else {
- /* Single threaded extraction. */
- (*task_counter)++;
- BLI_addtail(single_threaded_task_datas, taskdata);
- }
-}
-
-void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
- MeshBatchCache *cache,
- MeshBufferCache mbc,
- Mesh *me,
-
- const bool is_editmode,
- const bool is_paint_mode,
- const bool is_mode_active,
- const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const bool use_subsurf_fdots,
- const DRW_MeshCDMask *cd_layer_used,
- const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide)
-{
- /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
- * This sub-graph starts with an extract_render_data_node. This fills/converts the required data
- * from Mesh.
- *
- * Small extractions and extractions that can't be multi-threaded are grouped in a single
- * `extract_single_threaded_task_node`.
- *
- * Other extractions will create a node for each loop exceeding 8192 items. these nodes are
- * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the
- * user_data needed for the extraction based on the data extracted from the mesh.
- * counters are used to check if the finalize of a task has to be called.
- *
- * Mesh extraction sub graph
- *
- * +----------------------+
- * +-----> | extract_task1_loop_1 |
- * | +----------------------+
- * +------------------+ +----------------------+ +----------------------+
- * | mesh_render_data | --> | | --> | extract_task1_loop_2 |
- * +------------------+ | | +----------------------+
- * | | | +----------------------+
- * | | user_data_init | --> | extract_task2_loop_1 |
- * v | | +----------------------+
- * +------------------+ | | +----------------------+
- * | single_threaded | | | --> | extract_task2_loop_2 |
- * +------------------+ +----------------------+ +----------------------+
- * | +----------------------+
- * +-----> | extract_task2_loop_3 |
- * +----------------------+
- */
- eMRIterType iter_flag = 0;
- eMRDataType data_flag = 0;
-
- const bool do_lines_loose_subbuffer = mbc.ibo.lines_loose != NULL;
-
-#define TEST_ASSIGN(type, type_lowercase, name) \
- do { \
- if (DRW_TEST_ASSIGN_##type(mbc.type_lowercase.name)) { \
- iter_flag |= mesh_extract_iter_type(&extract_##name); \
- data_flag |= extract_##name.data_flag; \
- } \
- } while (0)
-
- TEST_ASSIGN(VBO, vbo, pos_nor);
- TEST_ASSIGN(VBO, vbo, lnor);
- TEST_ASSIGN(VBO, vbo, uv);
- TEST_ASSIGN(VBO, vbo, tan);
- TEST_ASSIGN(VBO, vbo, vcol);
- TEST_ASSIGN(VBO, vbo, sculpt_data);
- TEST_ASSIGN(VBO, vbo, orco);
- TEST_ASSIGN(VBO, vbo, edge_fac);
- TEST_ASSIGN(VBO, vbo, weights);
- TEST_ASSIGN(VBO, vbo, edit_data);
- TEST_ASSIGN(VBO, vbo, edituv_data);
- TEST_ASSIGN(VBO, vbo, edituv_stretch_area);
- TEST_ASSIGN(VBO, vbo, edituv_stretch_angle);
- TEST_ASSIGN(VBO, vbo, mesh_analysis);
- TEST_ASSIGN(VBO, vbo, fdots_pos);
- TEST_ASSIGN(VBO, vbo, fdots_nor);
- TEST_ASSIGN(VBO, vbo, fdots_uv);
- TEST_ASSIGN(VBO, vbo, fdots_edituv_data);
- TEST_ASSIGN(VBO, vbo, poly_idx);
- TEST_ASSIGN(VBO, vbo, edge_idx);
- TEST_ASSIGN(VBO, vbo, vert_idx);
- TEST_ASSIGN(VBO, vbo, fdot_idx);
- TEST_ASSIGN(VBO, vbo, skin_roots);
-
- TEST_ASSIGN(IBO, ibo, tris);
- TEST_ASSIGN(IBO, ibo, lines);
- TEST_ASSIGN(IBO, ibo, points);
- TEST_ASSIGN(IBO, ibo, fdots);
- TEST_ASSIGN(IBO, ibo, lines_paint_mask);
- TEST_ASSIGN(IBO, ibo, lines_adjacency);
- TEST_ASSIGN(IBO, ibo, edituv_tris);
- TEST_ASSIGN(IBO, ibo, edituv_lines);
- TEST_ASSIGN(IBO, ibo, edituv_points);
- TEST_ASSIGN(IBO, ibo, edituv_fdots);
-
- if (do_lines_loose_subbuffer) {
- iter_flag |= MR_ITER_LEDGE;
- }
-
-#undef TEST_ASSIGN
-
-#ifdef DEBUG_TIME
- double rdata_start = PIL_check_seconds_timer();
-#endif
-
- MeshRenderData *mr = mesh_render_data_create(me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- obmat,
- do_final,
- do_uvedit,
- cd_layer_used,
- ts,
- iter_flag,
- data_flag);
- mr->use_hide = use_hide;
- mr->use_subsurf_fdots = use_subsurf_fdots;
- mr->use_final_mesh = do_final;
-
-#ifdef DEBUG_TIME
- double rdata_end = PIL_check_seconds_timer();
-#endif
-
- size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t);
- int32_t *task_counters = MEM_callocN(counters_size, __func__);
- int counter_used = 0;
-
- struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create(
- task_graph, mr, iter_flag, data_flag);
- ExtractSingleThreadedTaskData *single_threaded_task_data = MEM_callocN(
- sizeof(ExtractSingleThreadedTaskData), __func__);
- UserDataInitTaskData *user_data_init_task_data = MEM_callocN(sizeof(UserDataInitTaskData),
- __func__);
- user_data_init_task_data->task_counters = task_counters;
- struct TaskNode *task_node_user_data_init = user_data_init_task_node_create(
- task_graph, user_data_init_task_data);
-
-#define EXTRACT(buf, name) \
- if (mbc.buf.name) { \
- extract_task_create(task_graph, \
- task_node_mesh_render_data, \
- task_node_user_data_init, \
- &single_threaded_task_data->task_datas, \
- &user_data_init_task_data->task_datas, \
- scene, \
- mr, \
- cache, \
- &extract_##name, \
- mbc.buf.name, \
- &task_counters[counter_used++]); \
- } \
- ((void)0)
-
- EXTRACT(vbo, pos_nor);
- EXTRACT(vbo, lnor);
- EXTRACT(vbo, uv);
- EXTRACT(vbo, tan);
- EXTRACT(vbo, vcol);
- EXTRACT(vbo, sculpt_data);
- EXTRACT(vbo, orco);
- EXTRACT(vbo, edge_fac);
- EXTRACT(vbo, weights);
- EXTRACT(vbo, edit_data);
- EXTRACT(vbo, edituv_data);
- EXTRACT(vbo, edituv_stretch_area);
- EXTRACT(vbo, edituv_stretch_angle);
- EXTRACT(vbo, mesh_analysis);
- EXTRACT(vbo, fdots_pos);
- EXTRACT(vbo, fdots_nor);
- EXTRACT(vbo, fdots_uv);
- EXTRACT(vbo, fdots_edituv_data);
- EXTRACT(vbo, poly_idx);
- EXTRACT(vbo, edge_idx);
- EXTRACT(vbo, vert_idx);
- EXTRACT(vbo, fdot_idx);
- EXTRACT(vbo, skin_roots);
-
- EXTRACT(ibo, tris);
- if (mbc.ibo.lines) {
- /* When `lines` and `lines_loose` are requested, schedule lines extraction that also creates
- * the `lines_loose` sub-buffer. */
- const MeshExtract *lines_extractor = do_lines_loose_subbuffer ?
- &extract_lines_with_lines_loose :
- &extract_lines;
- extract_task_create(task_graph,
- task_node_mesh_render_data,
- task_node_user_data_init,
- &single_threaded_task_data->task_datas,
- &user_data_init_task_data->task_datas,
- scene,
- mr,
- cache,
- lines_extractor,
- mbc.ibo.lines,
- &task_counters[counter_used++]);
- }
- else {
- if (do_lines_loose_subbuffer) {
- ExtractTaskData *taskdata = extract_task_data_create_lines_loose(mr, cache);
- BLI_addtail(&single_threaded_task_data->task_datas, taskdata);
- }
- }
- EXTRACT(ibo, points);
- EXTRACT(ibo, fdots);
- EXTRACT(ibo, lines_paint_mask);
- EXTRACT(ibo, lines_adjacency);
- EXTRACT(ibo, edituv_tris);
- EXTRACT(ibo, edituv_lines);
- EXTRACT(ibo, edituv_points);
- EXTRACT(ibo, edituv_fdots);
-
- /* Only create the edge when there is user data that needs to be initialized.
- * The task is still part of the graph so the task_data will be freed when the graph is freed.
- */
- if (!BLI_listbase_is_empty(&user_data_init_task_data->task_datas)) {
- BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init);
- }
-
- if (!BLI_listbase_is_empty(&single_threaded_task_data->task_datas)) {
- struct TaskNode *task_node = extract_single_threaded_task_node_create(
- task_graph, single_threaded_task_data);
- BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
- }
- else {
- extract_single_threaded_task_data_free(single_threaded_task_data);
- }
-
- /* Trigger the sub-graph for this mesh. */
- BLI_task_graph_node_push_work(task_node_mesh_render_data);
-
-#undef EXTRACT
-
-#ifdef DEBUG_TIME
- BLI_task_graph_work_and_wait(task_graph);
- double end = PIL_check_seconds_timer();
-
- static double avg = 0;
- static double avg_fps = 0;
- static double avg_rdata = 0;
- static double end_prev = 0;
-
- if (end_prev == 0) {
- end_prev = end;
- }
-
- avg = avg * 0.95 + (end - rdata_end) * 0.05;
- avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05;
- avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05;
-
- printf(
- "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000);
-
- end_prev = end;
-#endif
-}
-
-/** \} */
+ .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdot_idx)}; \ No newline at end of file
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
new file mode 100644
index 00000000000..d3acf10b72c
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
@@ -0,0 +1,515 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Extraction of Mesh data into VBO to feed to GPU.
+ */
+
+#pragma once
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_editmesh.h"
+
+#include "draw_cache_extract.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum eMRExtractType {
+ MR_EXTRACT_BMESH,
+ MR_EXTRACT_MAPPED,
+ MR_EXTRACT_MESH,
+} eMRExtractType;
+
+typedef struct MeshRenderData {
+ eMRExtractType extract_type;
+
+ int poly_len, edge_len, vert_len, loop_len;
+ int edge_loose_len;
+ int vert_loose_len;
+ int loop_loose_len;
+ int tri_len;
+ int mat_len;
+
+ bool use_hide;
+ bool use_subsurf_fdots;
+ bool use_final_mesh;
+
+ /** Use for #MeshStatVis calculation which use world-space coords. */
+ float obmat[4][4];
+
+ const ToolSettings *toolsettings;
+ /** Edit Mesh */
+ BMEditMesh *edit_bmesh;
+ BMesh *bm;
+ EditMeshData *edit_data;
+
+ /* For deformed edit-mesh data. */
+ /* Use for #ME_WRAPPER_TYPE_BMESH. */
+ const float (*bm_vert_coords)[3];
+ const float (*bm_vert_normals)[3];
+ const float (*bm_poly_normals)[3];
+ const float (*bm_poly_centers)[3];
+
+ int *v_origindex, *e_origindex, *p_origindex;
+ int crease_ofs;
+ int bweight_ofs;
+ int freestyle_edge_ofs;
+ int freestyle_face_ofs;
+ /** Mesh */
+ Mesh *me;
+ const MVert *mvert;
+ const MEdge *medge;
+ const MLoop *mloop;
+ const MPoly *mpoly;
+ BMVert *eve_act;
+ BMEdge *eed_act;
+ BMFace *efa_act;
+ BMFace *efa_act_uv;
+ /* Data created on-demand (usually not for #BMesh based data). */
+ MLoopTri *mlooptri;
+ float (*loop_normals)[3];
+ float (*poly_normals)[3];
+ int *lverts, *ledges;
+} MeshRenderData;
+
+BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_face_at_index(mr->bm, mr->p_origindex[idx]) :
+ NULL;
+}
+
+BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_edge_at_index(mr->bm, mr->e_origindex[idx]) :
+ NULL;
+}
+
+BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
+{
+ return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
+ BM_vert_at_index(mr->bm, mr->v_origindex[idx]) :
+ NULL;
+}
+
+BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
+{
+ const float(*vert_coords)[3] = mr->bm_vert_coords;
+ if (vert_coords != NULL) {
+ return vert_coords[BM_elem_index_get(eve)];
+ }
+
+ UNUSED_VARS(mr);
+ return eve->co;
+}
+
+BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
+{
+ const float(*vert_normals)[3] = mr->bm_vert_normals;
+ if (vert_normals != NULL) {
+ return vert_normals[BM_elem_index_get(eve)];
+ }
+
+ UNUSED_VARS(mr);
+ return eve->no;
+}
+
+BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
+{
+ const float(*poly_normals)[3] = mr->bm_poly_normals;
+ if (poly_normals != NULL) {
+ return poly_normals[BM_elem_index_get(efa)];
+ }
+
+ UNUSED_VARS(mr);
+ return efa->no;
+}
+
+/* TODO(jbakker): phase out batch iteration macros as they are only used once. */
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Elements Extract: Loop Triangles
+ * \{ */
+
+typedef struct ExtractTriBMesh_Params {
+ BMLoop *(*looptris)[3];
+ int tri_range[2];
+} ExtractTriBMesh_Params;
+typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
+ BMLoop **elt,
+ const int elt_index,
+ void *data);
+
+#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \
+ CHECK_TYPE(params, const ExtractTriBMesh_Params *); \
+ { \
+ const int _tri_index_end = (params)->tri_range[1]; \
+ BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \
+ for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
+ index_tri += 1, elem_tri += 3)
+#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END }
+
+typedef struct ExtractTriMesh_Params {
+ const MLoopTri *mlooptri;
+ int tri_range[2];
+} ExtractTriMesh_Params;
+typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
+ const MLoopTri *mlt,
+ const int elt_index,
+ void *data);
+
+#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \
+ CHECK_TYPE(params, const ExtractTriMesh_Params *); \
+ { \
+ const int _tri_index_end = (params)->tri_range[1]; \
+ const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \
+ for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
+ index_tri += 1, elem_tri += 1)
+#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END }
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Elements Extract: Polygons, Loops
+ * \{ */
+
+typedef struct ExtractPolyBMesh_Params {
+ BMLoop *(*looptris)[3];
+ int poly_range[2];
+} ExtractPolyBMesh_Params;
+typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
+ BMFace *f,
+ const int f_index,
+ void *data);
+
+#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \
+ CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
+ { \
+ BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
+ BMFace **_ftable = mr->bm->ftable; \
+ const int _poly_index_end = (params)->poly_range[1]; \
+ for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
+ index_poly += 1) { \
+ BMFace *elem_poly = _ftable[index_poly]; \
+ (void)elem_poly;
+
+#define EXTRACT_POLY_FOREACH_BM_END \
+ } \
+ }
+
+/* Iterate over polygon and loop. */
+#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \
+ CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
+ { \
+ BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
+ BMFace **_ftable = mr->bm->ftable; \
+ const int _poly_index_end = (params)->poly_range[1]; \
+ for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
+ index_poly += 1) { \
+ BMFace *elem_face = _ftable[index_poly]; \
+ BMLoop *elem_loop, *l_first; \
+ elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \
+ do { \
+ const int index_loop = BM_elem_index_get(elem_loop); \
+ (void)index_loop; /* Quiet warning when unused. */
+
+#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \
+ } \
+ while ((elem_loop = elem_loop->next) != l_first) \
+ ; \
+ } \
+ }
+
+typedef struct ExtractPolyMesh_Params {
+ int poly_range[2];
+} ExtractPolyMesh_Params;
+typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
+ const MPoly *mp,
+ const int mp_index,
+ void *data);
+
+#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \
+ CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
+ { \
+ const MPoly *_mpoly = mr->mpoly; \
+ const int _poly_index_end = (params)->poly_range[1]; \
+ for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
+ index_poly += 1) { \
+ const MPoly *elem_poly = &_mpoly[index_poly]; \
+ (void)elem_poly;
+
+#define EXTRACT_POLY_FOREACH_MESH_END \
+ } \
+ }
+
+/* Iterate over polygon and loop. */
+#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \
+ elem_poly, index_poly, elem_loop, index_loop, params, mr) \
+ CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
+ { \
+ const MPoly *_mpoly = mr->mpoly; \
+ const MLoop *_mloop = mr->mloop; \
+ const int _poly_index_end = (params)->poly_range[1]; \
+ for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
+ index_poly += 1) { \
+ const MPoly *elem_poly = &_mpoly[index_poly]; \
+ const int _index_end = elem_poly->loopstart + elem_poly->totloop; \
+ for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \
+ const MLoop *elem_loop = &_mloop[index_loop]; \
+ (void)elem_loop;
+
+#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \
+ } \
+ } \
+ }
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Elements Extract: Loose Edges
+ * \{ */
+
+typedef struct ExtractLEdgeBMesh_Params {
+ const int *ledge;
+ int ledge_range[2];
+} ExtractLEdgeBMesh_Params;
+typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
+ BMEdge *eed,
+ const int ledge_index,
+ void *data);
+
+#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \
+ CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \
+ { \
+ BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \
+ BMEdge **_etable = mr->bm->etable; \
+ const int *_ledge = (params)->ledge; \
+ const int _ledge_index_end = (params)->ledge_range[1]; \
+ for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
+ index_ledge += 1) { \
+ BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \
+ (void)elem_edge; /* Quiet warning when unused. */ \
+ {
+#define EXTRACT_LEDGE_FOREACH_BM_END \
+ } \
+ } \
+ }
+
+typedef struct ExtractLEdgeMesh_Params {
+ const int *ledge;
+ int ledge_range[2];
+} ExtractLEdgeMesh_Params;
+typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
+ const MEdge *med,
+ const uint ledge_index,
+ void *data);
+
+#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \
+ CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \
+ { \
+ const MEdge *_medge = mr->medge; \
+ const int *_ledge = (params)->ledge; \
+ const int _ledge_index_end = (params)->ledge_range[1]; \
+ for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
+ index_ledge += 1) { \
+ const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \
+ (void)elem_edge; /* Quiet warning when unused. */ \
+ {
+#define EXTRACT_LEDGE_FOREACH_MESH_END \
+ } \
+ } \
+ }
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Elements Extract: Loose Vertices
+ * \{ */
+
+typedef struct ExtractLVertBMesh_Params {
+ const int *lvert;
+ int lvert_range[2];
+} ExtractLVertBMesh_Params;
+typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
+ BMVert *eve,
+ const int lvert_index,
+ void *data);
+
+#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \
+ CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \
+ { \
+ BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
+ BMVert **vtable = mr->bm->vtable; \
+ const int *lverts = (params)->lvert; \
+ const int _lvert_index_end = (params)->lvert_range[1]; \
+ for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
+ index_lvert += 1) { \
+ BMVert *elem_vert = vtable[lverts[index_lvert]]; \
+ (void)elem_vert; /* Quiet warning when unused. */ \
+ {
+#define EXTRACT_LVERT_FOREACH_BM_END \
+ } \
+ } \
+ }
+
+typedef struct ExtractLVertMesh_Params {
+ const int *lvert;
+ int lvert_range[2];
+} ExtractLVertMesh_Params;
+typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
+ const MVert *mv,
+ const int lvert_index,
+ void *data);
+
+#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \
+ CHECK_TYPE(params, const ExtractLVertMesh_Params *); \
+ { \
+ const MVert *mvert = mr->mvert; \
+ const int *lverts = (params)->lvert; \
+ const int _lvert_index_end = (params)->lvert_range[1]; \
+ for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
+ index_lvert += 1) { \
+ const MVert *elem = &mvert[lverts[index_lvert]]; \
+ (void)elem; /* Quiet warning when unused. */ \
+ {
+#define EXTRACT_LVERT_FOREACH_MESH_END \
+ } \
+ } \
+ }
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh Elements Extract Struct
+ * \{ */
+
+typedef void *(ExtractInitFn)(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer);
+typedef void(ExtractFinishFn)(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *data);
+
+typedef struct MeshExtract {
+ /** Executed on main thread and return user data for iteration functions. */
+ ExtractInitFn *init;
+ /** Executed on one (or more if use_threading) worker thread(s). */
+ ExtractTriBMeshFn *iter_looptri_bm;
+ ExtractTriMeshFn *iter_looptri_mesh;
+ ExtractPolyBMeshFn *iter_poly_bm;
+ ExtractPolyMeshFn *iter_poly_mesh;
+ ExtractLEdgeBMeshFn *iter_ledge_bm;
+ ExtractLEdgeMeshFn *iter_ledge_mesh;
+ ExtractLVertBMeshFn *iter_lvert_bm;
+ ExtractLVertMeshFn *iter_lvert_mesh;
+ /** Executed on one worker thread after all elements iterations. */
+ ExtractFinishFn *finish;
+ /** Used to request common data. */
+ const eMRDataType data_type;
+ /** Used to know if the element callbacks are thread-safe and can be parallelized. */
+ const bool use_threading;
+ /**
+ * Offset in bytes of the buffer inside a MeshBufferCache instance. Points to a vertex or index
+ * buffer.
+ */
+ const size_t mesh_buffer_offset;
+} MeshExtract;
+
+/** \} */
+
+/* draw_cache_extract_mesh_render_data.c */
+MeshRenderData *mesh_render_data_create(Mesh *me,
+ MeshBufferExtractionCache *cache,
+ const bool is_editmode,
+ const bool is_paint_mode,
+ const bool is_mode_active,
+ const float obmat[4][4],
+ const bool do_final,
+ const bool do_uvedit,
+ const ToolSettings *ts,
+ const eMRIterType iter_type);
+void mesh_render_data_free(MeshRenderData *mr);
+void mesh_render_data_update_normals(MeshRenderData *mr,
+ const eMRDataType data_flag);
+void mesh_render_data_update_looptris(MeshRenderData *mr,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag);
+
+/* draw_cache_extract_mesh_extractors.c */
+void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc);
+eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
+const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
+ const bool do_hq_normals,
+ const bool do_lines_loose_subbuffer);
+/*
+ * Total number of extractions types.
+ */
+#define M_EXTRACT_LEN 38
+
+extern const MeshExtract extract_tris;
+extern const MeshExtract extract_lines;
+extern const MeshExtract extract_lines_with_lines_loose;
+extern const MeshExtract extract_points;
+extern const MeshExtract extract_fdots;
+extern const MeshExtract extract_lines_paint_mask;
+extern const MeshExtract extract_lines_adjacency;
+extern const MeshExtract extract_edituv_tris;
+extern const MeshExtract extract_edituv_lines;
+extern const MeshExtract extract_edituv_points;
+extern const MeshExtract extract_edituv_fdots;
+extern const MeshExtract extract_pos_nor;
+extern const MeshExtract extract_pos_nor_hq;
+extern const MeshExtract extract_lnor_hq;
+extern const MeshExtract extract_lnor;
+extern const MeshExtract extract_uv;
+extern const MeshExtract extract_tan;
+extern const MeshExtract extract_tan_hq;
+extern const MeshExtract extract_sculpt_data;
+extern const MeshExtract extract_vcol;
+extern const MeshExtract extract_orco;
+extern const MeshExtract extract_edge_fac;
+extern const MeshExtract extract_weights;
+extern const MeshExtract extract_edit_data;
+extern const MeshExtract extract_edituv_data;
+extern const MeshExtract extract_edituv_stretch_area;
+extern const MeshExtract extract_edituv_stretch_angle;
+extern const MeshExtract extract_mesh_analysis;
+extern const MeshExtract extract_fdots_pos;
+extern const MeshExtract extract_fdots_nor;
+extern const MeshExtract extract_fdots_nor_hq;
+extern const MeshExtract extract_fdots_uv;
+extern const MeshExtract extract_fdots_edituv_data;
+extern const MeshExtract extract_skin_roots;
+extern const MeshExtract extract_poly_idx;
+extern const MeshExtract extract_edge_idx;
+extern const MeshExtract extract_vert_idx;
+extern const MeshExtract extract_fdot_idx;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
new file mode 100644
index 00000000000..db28e4f3ba3
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
@@ -0,0 +1,372 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Extraction of Mesh data into VBO to feed to GPU.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_mesh.h"
+
+#include "GPU_batch.h"
+
+#include "ED_mesh.h"
+
+#include "draw_cache_extract_mesh_private.h"
+
+/* ---------------------------------------------------------------------- */
+/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
+ * \{ */
+
+static void mesh_render_data_loose_geom_load(MeshRenderData *mr, MeshBufferExtractionCache *cache)
+{
+ mr->ledges = cache->ledges;
+ mr->lverts = cache->lverts;
+ mr->vert_loose_len = cache->vert_loose_len;
+ mr->edge_loose_len = cache->edge_loose_len;
+
+ mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
+}
+
+static void mesh_render_data_loose_geom_ensure(const MeshRenderData *mr,
+ MeshBufferExtractionCache *cache)
+{
+ /* Early exit: Are loose geometry already available. Only checking for loose verts as loose edges
+ * and verts are calculated at the same time.*/
+ if (cache->lverts) {
+ return;
+ }
+
+ cache->vert_loose_len = 0;
+ cache->edge_loose_len = 0;
+
+ if (mr->extract_type != MR_EXTRACT_BMESH) {
+ /* Mesh */
+
+ BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
+
+ cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__);
+ const MEdge *med = mr->medge;
+ for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
+ if (med->flag & ME_LOOSEEDGE) {
+ cache->ledges[cache->edge_loose_len++] = med_index;
+ }
+ /* Tag verts as not loose. */
+ BLI_BITMAP_ENABLE(lvert_map, med->v1);
+ BLI_BITMAP_ENABLE(lvert_map, med->v2);
+ }
+ if (cache->edge_loose_len < mr->edge_len) {
+ cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges));
+ }
+
+ cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
+ for (int v = 0; v < mr->vert_len; v++) {
+ if (!BLI_BITMAP_TEST(lvert_map, v)) {
+ cache->lverts[cache->vert_loose_len++] = v;
+ }
+ }
+ if (cache->vert_loose_len < mr->vert_len) {
+ cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts));
+ }
+
+ MEM_freeN(lvert_map);
+ }
+ else {
+ /* #BMesh */
+ BMesh *bm = mr->bm;
+ int elem_id;
+ BMIter iter;
+ BMVert *eve;
+ BMEdge *ede;
+
+ cache->lverts = MEM_mallocN(mr->vert_len * sizeof(*cache->lverts), __func__);
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
+ if (eve->e == NULL) {
+ cache->lverts[cache->vert_loose_len++] = elem_id;
+ }
+ }
+ if (cache->vert_loose_len < mr->vert_len) {
+ cache->lverts = MEM_reallocN(cache->lverts, cache->vert_loose_len * sizeof(*cache->lverts));
+ }
+
+ cache->ledges = MEM_mallocN(mr->edge_len * sizeof(*cache->ledges), __func__);
+ BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
+ if (ede->l == NULL) {
+ cache->ledges[cache->edge_loose_len++] = elem_id;
+ }
+ }
+ if (cache->edge_loose_len < mr->edge_len) {
+ cache->ledges = MEM_reallocN(cache->ledges, cache->edge_loose_len * sizeof(*cache->ledges));
+ }
+ }
+}
+
+/**
+ * Part of the creation of the #MeshRenderData that happens in a thread.
+ */
+void mesh_render_data_update_looptris(MeshRenderData *mr,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag)
+{
+ Mesh *me = mr->me;
+ if (mr->extract_type != MR_EXTRACT_BMESH) {
+ /* Mesh */
+ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
+ mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri);
+ }
+ }
+ else {
+ /* #BMesh */
+ if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
+ /* Edit mode ensures this is valid, no need to calculate. */
+ BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
+ }
+ }
+}
+
+void mesh_render_data_update_normals(MeshRenderData *mr,
+ const eMRDataType data_flag)
+{
+ Mesh *me = mr->me;
+ const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
+ const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
+
+ if (mr->extract_type != MR_EXTRACT_BMESH) {
+ /* Mesh */
+ if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
+ mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__);
+ BKE_mesh_calc_normals_poly((MVert *)mr->mvert,
+ NULL,
+ mr->vert_len,
+ mr->mloop,
+ mr->mpoly,
+ mr->loop_len,
+ mr->poly_len,
+ mr->poly_normals,
+ true);
+ }
+ if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
+ mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
+ BKE_mesh_normals_loop_split(mr->me->mvert,
+ mr->vert_len,
+ mr->me->medge,
+ mr->edge_len,
+ mr->me->mloop,
+ mr->loop_normals,
+ mr->loop_len,
+ mr->me->mpoly,
+ mr->poly_normals,
+ mr->poly_len,
+ is_auto_smooth,
+ split_angle,
+ NULL,
+ clnors,
+ NULL);
+ }
+ }
+ else {
+ /* #BMesh */
+ if (data_flag & MR_DATA_POLY_NOR) {
+ /* Use #BMFace.no instead. */
+ }
+ if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
+
+ const float(*vert_coords)[3] = NULL;
+ const float(*vert_normals)[3] = NULL;
+ const float(*poly_normals)[3] = NULL;
+
+ if (mr->edit_data && mr->edit_data->vertexCos) {
+ vert_coords = mr->bm_vert_coords;
+ vert_normals = mr->bm_vert_normals;
+ poly_normals = mr->bm_poly_normals;
+ }
+
+ mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
+ BM_loops_calc_normal_vcos(mr->bm,
+ vert_coords,
+ vert_normals,
+ poly_normals,
+ is_auto_smooth,
+ split_angle,
+ mr->loop_normals,
+ NULL,
+ NULL,
+ clnors_offset,
+ false);
+ }
+ }
+}
+
+/**
+ * \param is_mode_active: When true, use the modifiers from the edit-data,
+ * otherwise don't use modifiers as they are not from this object.
+ */
+MeshRenderData *mesh_render_data_create(Mesh *me,
+ MeshBufferExtractionCache *cache,
+ const bool is_editmode,
+ const bool is_paint_mode,
+ const bool is_mode_active,
+ const float obmat[4][4],
+ const bool do_final,
+ const bool do_uvedit,
+ const ToolSettings *ts,
+ const eMRIterType iter_type)
+{
+ MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
+ mr->toolsettings = ts;
+ mr->mat_len = mesh_render_mat_len_get(me);
+
+ copy_m4_m4(mr->obmat, obmat);
+
+ if (is_editmode) {
+ BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
+ mr->bm = me->edit_mesh->bm;
+ mr->edit_bmesh = me->edit_mesh;
+ mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
+ mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
+
+ if (mr->edit_data) {
+ EditMeshData *emd = mr->edit_data;
+ if (emd->vertexCos) {
+ BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd);
+ BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd);
+ }
+
+ mr->bm_vert_coords = mr->edit_data->vertexCos;
+ mr->bm_vert_normals = mr->edit_data->vertexNos;
+ mr->bm_poly_normals = mr->edit_data->polyNos;
+ mr->bm_poly_centers = mr->edit_data->polyCos;
+ }
+
+ bool has_mdata = is_mode_active && (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
+ bool use_mapped = is_mode_active &&
+ (has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original);
+
+ int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;
+
+ BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types);
+ BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP);
+
+ mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false);
+ mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true);
+ mr->eed_act = BM_mesh_active_edge_get(mr->bm);
+ mr->eve_act = BM_mesh_active_vert_get(mr->bm);
+
+ mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
+ mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT);
+#ifdef WITH_FREESTYLE
+ mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE);
+ mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE);
+#endif
+
+ if (use_mapped) {
+ mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
+ mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
+ mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+
+ use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
+ }
+
+ mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH;
+
+ /* Seems like the mesh_eval_final do not have the right origin indices.
+ * Force not mapped in this case. */
+ if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
+ // mr->edit_bmesh = NULL;
+ mr->extract_type = MR_EXTRACT_MESH;
+ }
+ }
+ else {
+ mr->me = me;
+ mr->edit_bmesh = NULL;
+
+ bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
+ if (use_mapped) {
+ mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
+ mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
+ mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+
+ use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
+ }
+
+ mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH;
+ }
+
+ if (mr->extract_type != MR_EXTRACT_BMESH) {
+ /* Mesh */
+ mr->vert_len = mr->me->totvert;
+ mr->edge_len = mr->me->totedge;
+ mr->loop_len = mr->me->totloop;
+ mr->poly_len = mr->me->totpoly;
+ mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
+
+ mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
+ mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
+ mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP);
+ mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
+
+ mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
+ mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
+ mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ }
+ else {
+ /* #BMesh */
+ BMesh *bm = mr->bm;
+
+ mr->vert_len = bm->totvert;
+ mr->edge_len = bm->totedge;
+ mr->loop_len = bm->totloop;
+ mr->poly_len = bm->totface;
+ mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
+ }
+
+ if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
+ mesh_render_data_loose_geom_ensure(mr, cache);
+ mesh_render_data_loose_geom_load(mr, cache);
+ }
+
+ return mr;
+}
+
+void mesh_render_data_free(MeshRenderData *mr)
+{
+ MEM_SAFE_FREE(mr->mlooptri);
+ MEM_SAFE_FREE(mr->poly_normals);
+ MEM_SAFE_FREE(mr->loop_normals);
+
+ /* Loose geometry are owned by MeshBufferExtractionCache. */
+ mr->ledges = NULL;
+ mr->lverts = NULL;
+
+ MEM_freeN(mr);
+}
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc
index 5cf99db5485..ee6a47e3dc6 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curve.cc
@@ -843,6 +843,9 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata,
int edges_len_capacity = curve_render_data_overlay_edges_len_get(rdata) * 2;
int vbo_len_used = 0;
+#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? (v) : NULL))
+#define DRW_TEST_ASSIGN_IBO(v) (v = (DRW_ibo_requested(v) ? (v) : NULL))
+
if (DRW_TEST_ASSIGN_VBO(vbo_pos)) {
GPU_vertbuf_init_with_format(vbo_pos, &format_pos);
GPU_vertbuf_data_alloc(vbo_pos, verts_len_capacity);
@@ -863,6 +866,9 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata,
GPU_indexbuf_init(elbp_lines, GPU_PRIM_LINES, edges_len_capacity, verts_len_capacity);
}
+#undef DRW_TEST_ASSIGN_VBO
+#undef DRW_TEST_ASSIGN_IBO
+
int nu_id = 0;
for (Nurb *nu = (Nurb *)rdata->nurbs->first; nu; nu = nu->next, nu_id++) {
const BezTriple *bezt = nu->bezt;
diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c
index d606f70db9e..ee16cb1a022 100644
--- a/source/blender/draw/intern/draw_cache_impl_displist.c
+++ b/source/blender/draw/intern/draw_cache_impl_displist.c
@@ -532,6 +532,8 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(ListBase *lb,
GPUVertBufRaw uv_step = {0};
GPUVertBufRaw tan_step = {0};
+#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? (v) : NULL))
+
if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) {
GPU_vertbuf_init_with_format(vbo_pos_nor,
do_hq_normals ? &format_pos_nor_hq : &format_pos_nor);
@@ -550,6 +552,8 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(ListBase *lb,
GPU_vertbuf_attr_get_raw_data(vbo_tan, tan_id, &tan_step);
}
+#undef DRW_TEST_ASSIGN_VBO
+
BKE_displist_normals_add(lb);
LISTBASE_FOREACH (const DispList *, dl, lb) {
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 8d5fdcc5276..3cc71e47f28 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -707,6 +707,26 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
}
}
+static void mesh_buffer_cache_clear(MeshBufferCache *mbufcache)
+{
+ GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
+ GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
+ for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) {
+ GPU_VERTBUF_DISCARD_SAFE(vbos[i]);
+ }
+ for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) {
+ GPU_INDEXBUF_DISCARD_SAFE(ibos[i]);
+ }
+}
+
+static void mesh_buffer_extraction_cache_clear(MeshBufferExtractionCache *extraction_cache)
+{
+ MEM_SAFE_FREE(extraction_cache->lverts);
+ MEM_SAFE_FREE(extraction_cache->ledges);
+ extraction_cache->edge_loose_len = 0;
+ extraction_cache->vert_loose_len = 0;
+}
+
static void mesh_batch_cache_clear(Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -714,16 +734,13 @@ static void mesh_batch_cache_clear(Mesh *me)
return;
}
FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
- GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
- GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
- for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) {
- GPU_VERTBUF_DISCARD_SAFE(vbos[i]);
- }
- for (int i = 0; i < sizeof(mbufcache->ibo) / sizeof(void *); i++) {
- GPU_INDEXBUF_DISCARD_SAFE(ibos[i]);
- }
+ mesh_buffer_cache_clear(mbufcache);
}
+ mesh_buffer_extraction_cache_clear(&cache->final_extraction_cache);
+ mesh_buffer_extraction_cache_clear(&cache->cage_extraction_cache);
+ mesh_buffer_extraction_cache_clear(&cache->uv_cage_extraction_cache);
+
for (int i = 0; i < cache->mat_len; i++) {
GPU_INDEXBUF_DISCARD_SAFE(cache->final.tris_per_mat[i]);
}
@@ -1542,7 +1559,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (do_uvcage) {
mesh_buffer_cache_create_requested(task_graph,
cache,
- cache->uv_cage,
+ &cache->uv_cage,
+ &cache->uv_cage_extraction_cache,
me,
is_editmode,
is_paint_mode,
@@ -1551,7 +1569,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
false,
true,
false,
- &cache->cd_used,
scene,
ts,
true);
@@ -1560,7 +1577,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (do_cage) {
mesh_buffer_cache_create_requested(task_graph,
cache,
- cache->cage,
+ &cache->cage,
+ &cache->cage_extraction_cache,
me,
is_editmode,
is_paint_mode,
@@ -1569,7 +1587,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
false,
false,
use_subsurf_fdots,
- &cache->cd_used,
scene,
ts,
true);
@@ -1577,7 +1594,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_buffer_cache_create_requested(task_graph,
cache,
- cache->final,
+ &cache->final,
+ &cache->final_extraction_cache,
me,
is_editmode,
is_paint_mode,
@@ -1586,7 +1604,6 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
true,
false,
use_subsurf_fdots,
- &cache->cd_used,
scene,
ts,
use_hide);
diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h
index bfc714e5d6a..6e537a3bffa 100644
--- a/source/blender/draw/intern/draw_cache_inline.h
+++ b/source/blender/draw/intern/draw_cache_inline.h
@@ -40,10 +40,6 @@
(flag |= DRW_ibo_requested(ibo) ? (value) : 0)
#endif
-/* Test and assign NULL if test fails */
-#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? (v) : NULL))
-#define DRW_TEST_ASSIGN_IBO(v) (v = (DRW_ibo_requested(v) ? (v) : NULL))
-
BLI_INLINE GPUBatch *DRW_batch_request(GPUBatch **batch)
{
/* XXX TODO(fclem): We are writing to batch cache here. Need to make this thread safe. */
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index bf3b10bccd3..585e171adc5 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -88,8 +88,8 @@ extern char datatoc_common_hair_refine_comp_glsl[];
extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
/* TODO(jbakker): move shader creation to `draw_shaders` and add test cases. */
-/* TODO(jbakker): replace defines with `constexpr` to check compilation on all OSs. Currently the
- * APPLE codepath does not compile on other platforms and vice versa. */
+/* TODO(jbakker): replace defines with `constexpr` to check compilation on all OS's.
+ * Currently the `__APPLE__` code-path does not compile on other platforms and vice versa. */
#ifdef USE_COMPUTE_SHADERS
static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(refinement))
{
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index 33deae0b0a1..479f9cd1827 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -86,6 +86,8 @@ float safe_rcp(float a) { return (a != 0.0) ? (1.0 / a) : 0.0; }
vec2 safe_rcp(vec2 a) { return mix(vec2(0.0), (1.0 / a), notEqual(a, vec2(0.0))); }
vec4 safe_rcp(vec4 a) { return mix(vec4(0.0), (1.0 / a), notEqual(a, vec4(0.0))); }
+float safe_sqrt(float a) { return sqrt(max(a, 0.0)); }
+
float sqr(float a) { return a * a; }
vec2 sqr(vec2 a) { return a * a; }
vec3 sqr(vec3 a) { return a * a; }
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 8842274e017..e4f2de1f741 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -210,7 +210,7 @@ static bool stroke_elem_project(const struct CurveDrawData *cdd,
ED_view3d_depth_read_cached(depths, mval_i, 0, &depth_fl);
const double depth = (double)depth_fl;
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (ED_view3d_depth_unproject(region, mval_i, depth, r_location_world)) {
+ if (ED_view3d_depth_unproject_v3(region, mval_i, depth, r_location_world)) {
is_location_world_set = true;
if (r_normal_world) {
zero_v3(r_normal_world);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 4de97411059..ea3d921f2c5 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -42,6 +42,7 @@ struct SpaceImage;
struct ToolSettings;
struct ViewLayer;
struct bNode;
+struct bNodeTree;
struct wmKeyConfig;
/* uvedit_ops.c */
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 66ec57c8a31..52d69d12253 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -162,10 +162,10 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd,
bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
const int mval[2],
float r_normal[3]);
-bool ED_view3d_depth_unproject(const struct ARegion *region,
- const int mval[2],
- const double depth,
- float r_location_world[3]);
+bool ED_view3d_depth_unproject_v3(const struct ARegion *region,
+ const int mval[2],
+ const double depth,
+ float r_location_world[3]);
void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
/* Projection */
@@ -410,8 +410,13 @@ void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d,
const float obmat[4][4],
float r_pmat[4][4]);
-void ED_view3d_project(const struct ARegion *region, const float world[3], float r_region_co[3]);
-bool ED_view3d_unproject(
+void ED_view3d_project_v3(const struct ARegion *region,
+ const float world[3],
+ float r_region_co[3]);
+void ED_view3d_project_v2(const struct ARegion *region,
+ const float world[3],
+ float r_region_co[2]);
+bool ED_view3d_unproject_v3(
const struct ARegion *region, float regionx, float regiony, float regionz, float world[3]);
/* end */
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index d5fb0e4e744..6583fa31dbf 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -118,7 +118,8 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
if (eye->ptr.type == &RNA_CompositorNodeCryptomatteV2) {
eye->crypto_node = (bNode *)eye->ptr.data;
- eye->cryptomatte_session = ntreeCompositCryptomatteSession(eye->crypto_node);
+ eye->cryptomatte_session = ntreeCompositCryptomatteSession(CTX_data_scene(C),
+ eye->crypto_node);
eye->draw_handle_sample_text = WM_draw_cb_activate(CTX_wm_window(C), eyedropper_draw_cb, eye);
}
@@ -199,6 +200,57 @@ static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_lay
return false;
}
+static bool eyedropper_cryptomatte_sample_render_fl(const bNode *node,
+ const char *prefix,
+ const float fpos[2],
+ float r_col[3])
+{
+ bool success = false;
+ Scene *scene = (Scene *)node->id;
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+ Render *re = RE_GetSceneRender(scene);
+
+ if (re) {
+ RenderResult *rr = RE_AcquireResultRead(re);
+ if (rr) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ RenderLayer *render_layer = RE_GetRenderLayer(rr, view_layer->name);
+ success = eyedropper_cryptomatte_sample_renderlayer_fl(render_layer, prefix, fpos, r_col);
+ if (success) {
+ break;
+ }
+ }
+ }
+ RE_ReleaseResult(re);
+ }
+ return success;
+}
+
+static bool eyedropper_cryptomatte_sample_image_fl(const bNode *node,
+ NodeCryptomatte *crypto,
+ const char *prefix,
+ const float fpos[2],
+ float r_col[3])
+{
+ bool success = false;
+ Image *image = (Image *)node->id;
+ BLI_assert(GS(image->id.name) == ID_IM);
+ ImageUser *iuser = &crypto->iuser;
+
+ if (image && image->type == IMA_TYPE_MULTILAYER) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+ if (image->rr) {
+ LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) {
+ success = eyedropper_cryptomatte_sample_renderlayer_fl(render_layer, prefix, fpos, r_col);
+ if (success) {
+ break;
+ }
+ }
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ return success;
+}
static bool eyedropper_cryptomatte_sample_fl(
bContext *C, Eyedropper *eye, int mx, int my, float r_col[3])
@@ -255,53 +307,19 @@ static bool eyedropper_cryptomatte_sample_fl(
return false;
}
- bool success = false;
/* TODO(jbakker): Migrate this file to cc and use std::string as return param. */
char prefix[MAX_NAME + 1];
- ntreeCompositCryptomatteLayerPrefix(node, prefix, sizeof(prefix) - 1);
+ const Scene *scene = CTX_data_scene(C);
+ ntreeCompositCryptomatteLayerPrefix(scene, node, prefix, sizeof(prefix) - 1);
prefix[MAX_NAME] = '\0';
if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
- Scene *scene = (Scene *)node->id;
- BLI_assert(GS(scene->id.name) == ID_SCE);
- Render *re = RE_GetSceneRender(scene);
-
- if (re) {
- RenderResult *rr = RE_AcquireResultRead(re);
- if (rr) {
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- RenderLayer *render_layer = RE_GetRenderLayer(rr, view_layer->name);
- success = eyedropper_cryptomatte_sample_renderlayer_fl(
- render_layer, prefix, fpos, r_col);
- if (success) {
- break;
- }
- }
- }
- RE_ReleaseResult(re);
- }
+ return eyedropper_cryptomatte_sample_render_fl(node, prefix, fpos, r_col);
}
- else if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) {
- Image *image = (Image *)node->id;
- BLI_assert(GS(image->id.name) == ID_IM);
- ImageUser *iuser = &crypto->iuser;
-
- if (image && image->type == IMA_TYPE_MULTILAYER) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
- if (image->rr) {
- LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) {
- success = eyedropper_cryptomatte_sample_renderlayer_fl(
- render_layer, prefix, fpos, r_col);
- if (success) {
- break;
- }
- }
- }
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return eyedropper_cryptomatte_sample_image_fl(node, crypto, prefix, fpos, r_col);
}
-
- return success;
+ return false;
}
/**
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index b5cd9c7f60d..825b7d11aef 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -578,8 +578,8 @@ static void knife_input_ray_segment(KnifeTool_OpData *kcd,
float r_origin_ofs[3])
{
/* unproject to find view ray */
- ED_view3d_unproject(kcd->vc.region, mval[0], mval[1], 0.0f, r_origin);
- ED_view3d_unproject(kcd->vc.region, mval[0], mval[1], ofs, r_origin_ofs);
+ ED_view3d_unproject_v3(kcd->vc.region, mval[0], mval[1], 0.0f, r_origin);
+ ED_view3d_unproject_v3(kcd->vc.region, mval[0], mval[1], ofs, r_origin_ofs);
/* transform into object space */
mul_m4_v3(kcd->ob_imat, r_origin);
@@ -1745,7 +1745,7 @@ static bool point_is_visible(KnifeTool_OpData *kcd,
float view[3], p_ofs[3];
/* TODO: I think there's a simpler way to get the required raycast ray */
- ED_view3d_unproject(kcd->vc.region, s[0], s[1], 0.0f, view);
+ ED_view3d_unproject_v3(kcd->vc.region, s[0], s[1], 0.0f, view);
mul_m4_v3(kcd->ob_imat, view);
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 9ef2cce875f..1ff576504ce 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -525,7 +525,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
float d_a[3], d_b[3];
float d_a_proj[2], d_b_proj[2];
- float preview_plane_proj[4][3];
+ float preview_plane_proj[4][2];
const float y_axis_proj[2] = {0.0f, 1.0f};
mid_v3_v3v3(text_pos, cd->preview_plane[0], cd->preview_plane[2]);
@@ -534,7 +534,7 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
for (int i = 0; i < 4; i++) {
float preview_plane_world_space[3];
mul_v3_m4v3(preview_plane_world_space, active_object->obmat, cd->preview_plane[i]);
- ED_view3d_project(region, preview_plane_world_space, preview_plane_proj[i]);
+ ED_view3d_project_v2(region, preview_plane_world_space, preview_plane_proj[i]);
}
/* Get the initial X and Y axis of the basis from the edges of the Bounding Box face. */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index a87b5054efa..b9a3bc87e19 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1654,7 +1654,7 @@ static void object_transform_axis_target_calc_depth_init(struct XFormAxisData *x
if (center_tot) {
mul_v3_fl(center, 1.0f / center_tot);
float center_proj[3];
- ED_view3d_project(xfd->vc.region, center, center_proj);
+ ED_view3d_project_v3(xfd->vc.region, center, center_proj);
xfd->prev.depth = center_proj[2];
xfd->prev.is_depth_valid = true;
}
@@ -1890,7 +1890,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
xfd->prev.depth = depth_fl;
xfd->prev.is_depth_valid = true;
- if (ED_view3d_depth_unproject(region, event->mval, depth, location_world)) {
+ if (ED_view3d_depth_unproject_v3(region, event->mval, depth, location_world)) {
if (is_translate) {
float normal[3];
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 5b545784e5b..97994b65f40 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -609,7 +609,7 @@ static bool key_test_depth(const PEData *data, const float co[3], const int scre
}
float win[3];
- ED_view3d_project(data->vc.region, co, win);
+ ED_view3d_project_v3(data->vc.region, co, win);
if (win[2] - 0.00001f > depth) {
return 0;
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 3829aeebbeb..7e111905883 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1039,7 +1039,7 @@ static void cursor_draw_point_screen_space(const uint gpuattr,
float translation_vertex_cursor[3], location[3];
copy_v3_v3(location, true_location);
mul_m4_v3(obmat, location);
- ED_view3d_project(region, location, translation_vertex_cursor);
+ ED_view3d_project_v3(region, location, translation_vertex_cursor);
/* Do not draw points behind the view. Z [near, far] is mapped to [-1, 1]. */
if (translation_vertex_cursor[2] <= 1.0f) {
imm_draw_circle_fill_3d(
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index b6ae6f8bee7..da34723eed4 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1239,10 +1239,9 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
}));
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
- int tottri;
BMLoop *(*looptris)[3];
looptris = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
- BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
+ BM_mesh_calc_tessellation_beauty(bm, looptris);
BMIter iter;
int i;
@@ -1290,7 +1289,7 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
break;
}
BM_mesh_boolean(
- bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, false, boolean_mode);
+ bm, looptris, looptris_tot, bm_face_isect_pair, NULL, 2, true, true, false, boolean_mode);
}
MEM_freeN(looptris);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index b093f07226e..59a5ad63f0e 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -846,7 +846,7 @@ static int paint_space_stroke(bContext *C,
while (length > 0.0f) {
float spacing = paint_space_stroke_spacing_variable(
C, scene, stroke, pressure, dpressure, length);
- float mouse[3];
+ float mouse[2];
if (length >= spacing) {
if (use_scene_spacing) {
@@ -856,7 +856,7 @@ static int paint_space_stroke(bContext *C,
add_v3_v3v3(final_world_space_position,
stroke->last_world_space_position,
final_world_space_position);
- ED_view3d_project(region, final_world_space_position, mouse);
+ ED_view3d_project_v2(region, final_world_space_position, mouse);
}
else {
mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
@@ -1240,7 +1240,7 @@ static void paint_line_strokes_spacing(bContext *C,
mul_v3_v3fl(final_world_space_position, d_world_space_position, spacing_final);
add_v3_v3v3(
final_world_space_position, world_space_position_old, final_world_space_position);
- ED_view3d_project(region, final_world_space_position, mouse);
+ ED_view3d_project_v2(region, final_world_space_position, mouse);
}
else {
mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 2e1dd928f96..d6d54a1985d 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1854,7 +1854,7 @@ static void flip_v3(float v[3], const ePaintSymmetryFlags symm)
flip_v3_v3(v, v, symm);
}
-static void flip_qt(float quat[3], const ePaintSymmetryFlags symm)
+static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
{
flip_qt_qt(quat, quat, symm);
}
@@ -4196,7 +4196,7 @@ void SCULPT_flip_v3_by_symm_area(float v[3],
}
}
-void SCULPT_flip_quat_by_symm_area(float quat[3],
+void SCULPT_flip_quat_by_symm_area(float quat[4],
const ePaintSymmetryFlags symm,
const ePaintSymmetryAreas symmarea,
const float pivot[3])
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 087cb6dd94a..e2ee4c9fed3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -278,7 +278,7 @@ void SCULPT_flip_v3_by_symm_area(float v[3],
const ePaintSymmetryFlags symm,
const ePaintSymmetryAreas symmarea,
const float pivot[3]);
-void SCULPT_flip_quat_by_symm_area(float quat[3],
+void SCULPT_flip_quat_by_symm_area(float quat[4],
const ePaintSymmetryFlags symm,
const ePaintSymmetryAreas symmarea,
const float pivot[3]);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 6b4366b2966..f11f1c01019 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -2753,11 +2753,10 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po
#else
/* Always supported through Accelerate framework BNNS on macOS. */
# ifndef __APPLE__
- if (!BLI_cpu_support_sse41())
-# endif
- {
+ if (!BLI_cpu_support_sse41()) {
uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
}
+# endif
#endif
uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, NULL, ICON_NONE);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index ebd4c0090b4..53ddc818cd1 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -3053,7 +3053,7 @@ static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
scene->r.efra = efra;
}
- WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME_RANGE, scene);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index cfc11afce13..867b8e3d40a 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -807,7 +807,7 @@ static bool select_linked_internal(Scene *scene)
bool changed = false;
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
- if ((seq->flag & SELECT) != 0) {
+ if ((seq->flag & SELECT) == 0) {
continue;
}
/* Only get unselected neighbors. */
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 967ad966320..8b6d0e9ee04 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3666,8 +3666,8 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* convert border to 3d coordinates */
- if ((!ED_view3d_unproject(region, cent[0], cent[1], depth_close, p)) ||
- (!ED_view3d_unproject(region, rect.xmin, rect.ymin, depth_close, p_corner))) {
+ if ((!ED_view3d_unproject_v3(region, cent[0], cent[1], depth_close, p)) ||
+ (!ED_view3d_unproject_v3(region, rect.xmin, rect.ymin, depth_close, p_corner))) {
return OPERATOR_CANCELLED;
}
@@ -3690,7 +3690,8 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
new_dist = rv3d->dist;
/* convert the drawn rectangle into 3d space */
- if (depth_close != FLT_MAX && ED_view3d_unproject(region, cent[0], cent[1], depth_close, p)) {
+ if (depth_close != FLT_MAX &&
+ ED_view3d_unproject_v3(region, cent[0], cent[1], depth_close, p)) {
negate_v3_v3(new_ofs, p);
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
index 298a2a7a824..07c3b6bd1d8 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
@@ -154,10 +154,10 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int
* Only pre-select a vertex when the cursor is really close to it. */
if (eve_test) {
BMVert *vert = (BMVert *)eve_test;
- float vert_p_co[3], vert_co[3];
+ float vert_p_co[2], vert_co[3];
const float mval_f[2] = {UNPACK2(vc.mval)};
mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->obmat, vert->co);
- ED_view3d_project(vc.region, vert_co, vert_p_co);
+ ED_view3d_project_v2(vc.region, vert_co, vert_p_co);
float len = len_v2v2(vert_p_co, mval_f);
if (len < 35) {
best.ele = (BMElem *)eve_test;
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 24d34e514c5..7547f8ee434 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -809,23 +809,30 @@ void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d,
/**
* Convert between region relative coordinates (x,y) and depth component z and
* a point in world space. */
-void ED_view3d_project(const struct ARegion *region, const float world[3], float r_region_co[3])
+void ED_view3d_project_v3(const struct ARegion *region, const float world[3], float r_region_co[3])
{
/* Viewport is set up to make coordinates relative to the region, not window. */
RegionView3D *rv3d = region->regiondata;
const int viewport[4] = {0, 0, region->winx, region->winy};
+ GPU_matrix_project_3fv(world, rv3d->viewmat, rv3d->winmat, viewport, r_region_co);
+}
- GPU_matrix_project(world, rv3d->viewmat, rv3d->winmat, viewport, r_region_co);
+void ED_view3d_project_v2(const struct ARegion *region, const float world[3], float r_region_co[2])
+{
+ /* Viewport is set up to make coordinates relative to the region, not window. */
+ RegionView3D *rv3d = region->regiondata;
+ const int viewport[4] = {0, 0, region->winx, region->winy};
+ GPU_matrix_project_2fv(world, rv3d->viewmat, rv3d->winmat, viewport, r_region_co);
}
-bool ED_view3d_unproject(
+bool ED_view3d_unproject_v3(
const struct ARegion *region, float regionx, float regiony, float regionz, float world[3])
{
RegionView3D *rv3d = region->regiondata;
const int viewport[4] = {0, 0, region->winx, region->winy};
const float region_co[3] = {regionx, regiony, regionz};
- return GPU_matrix_unproject(region_co, rv3d->viewmat, rv3d->winmat, viewport, world);
+ return GPU_matrix_unproject_3fv(region_co, rv3d->viewmat, rv3d->winmat, viewport, world);
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index f96c17d7cff..8ae5d4a29e9 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -299,8 +299,8 @@ void ED_view3d_clipping_calc(
float xs = (ELEM(val, 0, 3)) ? rect->xmin : rect->xmax;
float ys = (ELEM(val, 0, 1)) ? rect->ymin : rect->ymax;
- ED_view3d_unproject(region, xs, ys, 0.0, bb->vec[val]);
- ED_view3d_unproject(region, xs, ys, 1.0, bb->vec[4 + val]);
+ ED_view3d_unproject_v3(region, xs, ys, 0.0, bb->vec[val]);
+ ED_view3d_unproject_v3(region, xs, ys, 1.0, bb->vec[4 + val]);
}
/* optionally transform to object space */
@@ -1057,7 +1057,7 @@ bool ED_view3d_autodist(Depsgraph *depsgraph,
float centx = (float)mval[0] + 0.5f;
float centy = (float)mval[1] + 0.5f;
- if (ED_view3d_unproject(region, centx, centy, depth_close, mouse_worldloc)) {
+ if (ED_view3d_unproject_v3(region, centx, centy, depth_close, mouse_worldloc)) {
return true;
}
}
@@ -1091,7 +1091,7 @@ bool ED_view3d_autodist_simple(ARegion *region,
float centx = (float)mval[0] + 0.5f;
float centy = (float)mval[1] + 0.5f;
- return ED_view3d_unproject(region, centx, centy, depth, mouse_worldloc);
+ return ED_view3d_unproject_v3(region, centx, centy, depth, mouse_worldloc);
}
bool ED_view3d_autodist_depth(ARegion *region, const int mval[2], int margin, float *depth)
@@ -1716,7 +1716,7 @@ bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
ED_view3d_depth_read_cached(depths, mval_ofs, 0, &depth_fl);
const double depth = (double)depth_fl;
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (ED_view3d_depth_unproject(region, mval_ofs, depth, coords[i])) {
+ if (ED_view3d_depth_unproject_v3(region, mval_ofs, depth, coords[i])) {
depths_valid[i] = true;
}
}
@@ -1751,14 +1751,14 @@ bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
return false;
}
-bool ED_view3d_depth_unproject(const ARegion *region,
- const int mval[2],
- const double depth,
- float r_location_world[3])
+bool ED_view3d_depth_unproject_v3(const ARegion *region,
+ const int mval[2],
+ const double depth,
+ float r_location_world[3])
{
float centx = (float)mval[0] + 0.5f;
float centy = (float)mval[1] + 0.5f;
- return ED_view3d_unproject(region, centx, centy, depth, r_location_world);
+ return ED_view3d_unproject_v3(region, centx, centy, depth, r_location_world);
}
void ED_view3d_depth_tag_update(RegionView3D *rv3d)
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
index aad6ae9e2ba..e073263f352 100644
--- a/source/blender/gpu/GPU_matrix.h
+++ b/source/blender/gpu/GPU_matrix.h
@@ -118,21 +118,27 @@ bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *unproj_prec
const float proj[4][4],
const int view[4]);
-void GPU_matrix_project(const float world[3],
- const float model[4][4],
- const float proj[4][4],
- const int view[4],
- float r_win[3]);
-
-bool GPU_matrix_unproject(const float win[3],
- const float model[4][4],
- const float proj[4][4],
- const int view[4],
- float r_world[3]);
-
-void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *unproj_precalc,
- const float win[3],
- float r_world[3]);
+void GPU_matrix_project_3fv(const float world[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float r_win[3]);
+
+void GPU_matrix_project_2fv(const float world[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float r_win[2]);
+
+bool GPU_matrix_unproject_3fv(const float win[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float r_world[3]);
+
+void GPU_matrix_unproject_3fv_with_precalc(const struct GPUMatrixUnproject_Precalc *unproj_precalc,
+ const float win[3],
+ float r_world[3]);
/* 2D Projection Matrix */
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc
index 569b51a407a..6eb9cb823d5 100644
--- a/source/blender/gpu/intern/gpu_matrix.cc
+++ b/source/blender/gpu/intern/gpu_matrix.cc
@@ -474,11 +474,11 @@ void GPU_matrix_look_at(float eyeX,
GPU_matrix_translate_3f(-eyeX, -eyeY, -eyeZ);
}
-void GPU_matrix_project(const float world[3],
- const float model[4][4],
- const float proj[4][4],
- const int view[4],
- float win[3])
+void GPU_matrix_project_3fv(const float world[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float win[3])
{
float v[4];
@@ -494,6 +494,25 @@ void GPU_matrix_project(const float world[3],
win[2] = (v[2] + 1) * 0.5f;
}
+void GPU_matrix_project_2fv(const float world[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float win[2])
+{
+ float v[4];
+
+ mul_v4_m4v3(v, model, world);
+ mul_m4_v4(proj, v);
+
+ if (v[3] != 0.0f) {
+ mul_v2_fl(v, 1.0f / v[3]);
+ }
+
+ win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f;
+ win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f;
+}
+
/**
* The same result could be obtained as follows:
*
@@ -556,9 +575,9 @@ bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *precalc,
return true;
}
-void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *precalc,
- const float win[3],
- float r_world[3])
+void GPU_matrix_unproject_3fv_with_precalc(const struct GPUMatrixUnproject_Precalc *precalc,
+ const float win[3],
+ float r_world[3])
{
float in[3] = {
(win[0] - precalc->view[0]) / precalc->view[2],
@@ -569,18 +588,18 @@ void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *
mul_v3_m4v3(r_world, precalc->model_inverted, in);
}
-bool GPU_matrix_unproject(const float win[3],
- const float model[4][4],
- const float proj[4][4],
- const int view[4],
- float r_world[3])
+bool GPU_matrix_unproject_3fv(const float win[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float r_world[3])
{
struct GPUMatrixUnproject_Precalc precalc;
if (!GPU_matrix_unproject_precalc(&precalc, model, proj, view)) {
zero_v3(r_world);
return false;
}
- GPU_matrix_unproject_with_precalc(&precalc, win, r_world);
+ GPU_matrix_unproject_3fv_with_precalc(&precalc, win, r_world);
return true;
}
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 11ce77e3091..e1e6cc677ed 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -466,13 +466,6 @@ struct proxy_output_ctx {
struct anim *anim;
};
-// work around stupid swscaler 16 bytes alignment bug...
-
-static int round_up(int x, int mod)
-{
- return x + ((mod - (x % mod)) % mod);
-}
-
static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
struct anim *anim, AVStream *st, int proxy_size, int width, int height, int quality)
{
@@ -499,13 +492,6 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
rv->c = avcodec_alloc_context3(NULL);
rv->c->codec_type = AVMEDIA_TYPE_VIDEO;
rv->c->codec_id = AV_CODEC_ID_H264;
- rv->c->width = width;
- rv->c->height = height;
- rv->c->gop_size = 10;
- rv->c->max_b_frames = 0;
- /* Correct wrong default ffmpeg param which crash x264. */
- rv->c->qmin = 10;
- rv->c->qmax = 51;
rv->of->oformat->video_codec = rv->c->codec_id;
rv->codec = avcodec_find_encoder(rv->c->codec_id);
@@ -520,6 +506,13 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
return NULL;
}
+ avcodec_get_context_defaults3(rv->c, rv->codec);
+
+ rv->c->width = width;
+ rv->c->height = height;
+ rv->c->gop_size = 10;
+ rv->c->max_b_frames = 0;
+
if (rv->codec->pix_fmts) {
rv->c->pix_fmt = rv->codec->pix_fmts[0];
}
@@ -595,15 +588,19 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
if (st->codecpar->width != width || st->codecpar->height != height ||
st->codecpar->format != rv->c->pix_fmt) {
rv->frame = av_frame_alloc();
- av_image_fill_arrays(
- rv->frame->data,
- rv->frame->linesize,
- MEM_mallocN(av_image_get_buffer_size(rv->c->pix_fmt, round_up(width, 16), height, 1),
- "alloc proxy output frame"),
- rv->c->pix_fmt,
- round_up(width, 16),
- height,
- 1);
+
+ av_image_fill_arrays(rv->frame->data,
+ rv->frame->linesize,
+ MEM_mallocN(av_image_get_buffer_size(rv->c->pix_fmt, width, height, 1),
+ "alloc proxy output frame"),
+ rv->c->pix_fmt,
+ width,
+ height,
+ 1);
+
+ rv->frame->format = rv->c->pix_fmt;
+ rv->frame->width = width;
+ rv->frame->height = height;
rv->sws_ctx = sws_getContext(st->codecpar->width,
rv->orig_height,
@@ -686,6 +683,9 @@ static void add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *fr
packet->stream_index = ctx->st->index;
av_packet_rescale_ts(packet, ctx->c->time_base, ctx->st->time_base);
+# ifdef FFMPEG_USE_DURATION_WORKAROUND
+ my_guess_pkt_duration(ctx->of, ctx->st, packet);
+# endif
int write_ret = av_interleaved_write_frame(ctx->of, packet);
if (write_ret != 0) {
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 58c94b6f369..0fa1d1a74ac 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -461,7 +461,6 @@ typedef struct bNodeTree {
short is_updating;
/** Generic temporary flag for recursion check (DFS/BFS). */
short done;
- char _pad2[4];
/** Specific node type this tree is used for. */
int nodetype DNA_DEPRECATED;
@@ -472,6 +471,8 @@ typedef struct bNodeTree {
short render_quality;
/** Tile size for compositor engine. */
int chunksize;
+ /** Execution mode to use for compositor engine. */
+ int execution_mode;
rctf viewer_border;
@@ -545,6 +546,12 @@ typedef enum eNodeTreeUpdate {
NTREE_UPDATE_GROUP = (NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_GROUP_OUT),
} eNodeTreeUpdate;
+/* tree->execution_mode */
+typedef enum eNodeTreeExecutionMode {
+ NTREE_EXECUTION_MODE_TILED = 0,
+ NTREE_EXECUTION_MODE_FULL_FRAME = 1,
+} eNodeTreeExecutionMode;
+
/* socket value structs for input buttons
* DEPRECATED now using ID properties
*/
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 4b95dd41b30..f59f51ea28a 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -57,6 +57,7 @@ typedef struct StripElem {
char name[256];
/** Ignore when zeroed. */
int orig_width, orig_height;
+ float orig_fps;
} StripElem;
typedef struct StripCrop {
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 1fed8e14bd6..61d2c04d98b 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -642,11 +642,12 @@ typedef struct UserDef_Experimental {
* when the release cycle is not alpha. */
char use_new_hair_type;
char use_new_point_cloud_type;
+ char use_full_frame_compositor;
char use_sculpt_vertex_colors;
char use_sculpt_tools_tilt;
char use_asset_browser;
char use_override_templates;
- char _pad[6];
+ char _pad[5];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 150a455f1c7..948fef1b51e 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -6115,13 +6115,25 @@ char *RNA_path_full_ID_py(Main *bmain, ID *id)
path = "";
}
- char id_esc[(sizeof(id->name) - 2) * 2];
+ char lib_filepath_esc[(sizeof(id->lib->filepath) * 2) + 4];
+ if (id->lib != NULL) {
+ int ofs = 0;
+ memcpy(lib_filepath_esc, ", \"", 3);
+ ofs += 3;
+ ofs += BLI_str_escape(lib_filepath_esc + ofs, id->lib->filepath, sizeof(lib_filepath_esc));
+ memcpy(lib_filepath_esc + ofs, "\"", 2);
+ }
+ else {
+ lib_filepath_esc[0] = '\0';
+ }
+ char id_esc[(sizeof(id->name) - 2) * 2];
BLI_str_escape(id_esc, id->name + 2, sizeof(id_esc));
- return BLI_sprintfN("bpy.data.%s[\"%s\"]%s%s",
+ return BLI_sprintfN("bpy.data.%s[\"%s\"%s]%s%s",
BKE_idtype_idcode_to_name_plural(GS(id->name)),
id_esc,
+ lib_filepath_esc,
path[0] ? "." : "",
path);
}
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 206ebc2cb14..54f9a93d90a 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -650,7 +650,7 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain,
seq->strip->proxy->anim = NULL;
}
- SEQ_relations_invalidate_cache_preprocessed(scene, seq);
+ SEQ_relations_invalidate_cache_raw(scene, seq);
}
else {
SEQ_ALL_BEGIN (scene->ed, seq) {
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index abc96ddc820..e5e7564f578 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -1376,7 +1376,7 @@ static void rna_def_charinfo(BlenderRNA *brna)
prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
// RNA_def_property_int_sdna(prop, NULL, "mat_nr");
- RNA_def_property_ui_text(prop, "Material Index", "");
+ RNA_def_property_ui_text(prop, "Material Index", "Material slot index of this character");
RNA_def_property_int_funcs(prop,
"rna_ChariInfo_material_index_get",
"rna_ChariInfo_material_index_set",
@@ -2068,7 +2068,7 @@ static void rna_def_curve_nurb(BlenderRNA *brna)
prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "mat_nr");
- RNA_def_property_ui_text(prop, "Material Index", "");
+ RNA_def_property_ui_text(prop, "Material Index", "Material slot index of this curve");
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_Curve_material_index_range");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 5f865f9d4cd..19ed5f960cf 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -1625,7 +1625,7 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
/* Material Index */
prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "mat_nr");
- RNA_def_property_ui_text(prop, "Material Index", "Index of material used in this stroke");
+ RNA_def_property_ui_text(prop, "Material Index", "Material slot index of this stroke");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Settings */
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index f772f9b5573..d5a1047d287 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -1823,7 +1823,7 @@ static void rna_def_mlooptri(BlenderRNA *brna)
prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_int_funcs(prop, "rna_MeshLoopTriangle_material_index_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Material Index", "");
+ RNA_def_property_ui_text(prop, "Material Index", "Material slot index of this triangle");
prop = RNA_def_property(srna, "use_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1933,7 +1933,7 @@ static void rna_def_mpolygon(BlenderRNA *brna)
prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "mat_nr");
- RNA_def_property_ui_text(prop, "Material Index", "");
+ RNA_def_property_ui_text(prop, "Material Index", "Material slot index of this polygon");
# if 0
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range");
# endif
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 11f5ff0441a..f5cbb694554 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -127,6 +127,20 @@ static const EnumPropertyItem node_chunksize_items[] = {
};
#endif
+static const EnumPropertyItem rna_enum_execution_mode_items[] = {
+ {NTREE_EXECUTION_MODE_TILED,
+ "TILED",
+ 0,
+ "Tiled",
+ "Compositing is tiled, having as priority to display first tiles as fast as possible"},
+ {NTREE_EXECUTION_MODE_FULL_FRAME,
+ "FULL_FRAME",
+ 0,
+ "Full Frame",
+ "Composites full image result as fast as possible"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_mapping_type_items[] = {
{NODE_MAPPING_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
{NODE_MAPPING_TYPE_TEXTURE,
@@ -3973,7 +3987,7 @@ static void rna_NodeCryptomatte_layer_name_set(PointerRNA *ptr, int new_value)
}
}
-static const EnumPropertyItem *rna_NodeCryptomatte_layer_name_itemf(bContext *UNUSED(C),
+static const EnumPropertyItem *rna_NodeCryptomatte_layer_name_itemf(bContext *C,
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
bool *r_free)
@@ -3984,7 +3998,7 @@ static const EnumPropertyItem *rna_NodeCryptomatte_layer_name_itemf(bContext *UN
EnumPropertyItem template = {0, "", 0, "", ""};
int totitem = 0;
- ntreeCompositCryptomatteUpdateLayerNames(node);
+ ntreeCompositCryptomatteUpdateLayerNames(CTX_data_scene(C), node);
int layer_index;
LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, layer_index) {
template.value = layer_index;
@@ -4076,7 +4090,7 @@ static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value)
static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- ntreeCompositCryptomatteSyncFromAdd(ptr->data);
+ ntreeCompositCryptomatteSyncFromAdd(scene, ptr->data);
rna_Node_update(bmain, scene, ptr);
}
@@ -9236,12 +9250,12 @@ static void def_geo_attribute_attribute_compare(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_any);
+ RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean);
RNA_def_property_ui_text(prop, "Input Type A", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_any);
+ RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean);
RNA_def_property_ui_text(prop, "Input Type B", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
@@ -11671,6 +11685,12 @@ static void rna_def_composite_nodetree(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "bNodeTree");
RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS);
+ prop = RNA_def_property(srna, "execution_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "execution_mode");
+ RNA_def_property_enum_items(prop, rna_enum_execution_mode_items);
+ RNA_def_property_ui_text(prop, "Execution Mode", "Set how compositing is executed");
+ RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
+
prop = RNA_def_property(srna, "render_quality", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "render_quality");
RNA_def_property_enum_items(prop, node_quality_items);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 9ba92431723..8fbad449cf6 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -1346,6 +1346,11 @@ static void rna_def_strip_element(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "orig_height");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Orig Height", "Original image height");
+
+ prop = RNA_def_property(srna, "orig_fps", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "orig_fps");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Orig FPS", "Original frames per second");
}
static void rna_def_strip_crop(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index d744f67c6f6..0af2572a4bd 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -5466,7 +5466,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_PROXIES);
RNA_def_property_ui_text(
prop, "Use Proxies", "Use optimized files for faster scrubbing when available");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_update_cache");
/* grease pencil */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index bacd3943141..6005ec96255 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6276,6 +6276,14 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "New Point Cloud Type", "Enable the new point cloud type in the ui");
+ prop = RNA_def_property(srna, "use_full_frame_compositor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_full_frame_compositor", 1);
+ RNA_def_property_ui_text(prop,
+ "Full Frame Compositor",
+ "Enable compositor full frame execution mode option (no tiling, "
+ "reduces execution time and memory usage)");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "use_new_hair_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_new_hair_type", 1);
RNA_def_property_ui_text(prop, "New Hair Type", "Enable the new hair type in the ui");
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 91327b97fe4..0138dd0c3ad 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -195,7 +195,11 @@ endif()
if(WITH_TBB)
add_definitions(-DWITH_TBB)
-
+ if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+ endif()
list(APPEND INC_SYS
${TBB_INCLUDE_DIRS}
)
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index 9b8782737c3..4b9b24e4e47 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -283,11 +283,10 @@ static void BMD_mesh_intersection(BMesh *bm,
/* main bmesh intersection setup */
/* create tessface & intersect */
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
- int tottri;
BMLoop *(*looptris)[3] = (BMLoop * (*)[3])
MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
- BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
+ BM_mesh_calc_tessellation_beauty(bm, looptris);
/* postpone this until after tessellating
* so we can use the original normals before the vertex are moved */
@@ -364,7 +363,7 @@ static void BMD_mesh_intersection(BMesh *bm,
BM_mesh_intersect(bm,
looptris,
- tottri,
+ looptris_tot,
bm_face_isect_pair,
nullptr,
false,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index d2c011a21d3..bfd4cd81803 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -184,13 +184,17 @@ static void deformVerts(ModifierData *md,
surmd->cfra = cfra;
- surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh");
+ const bool has_poly = surmd->mesh->totpoly > 0;
+ const bool has_edge = surmd->mesh->totedge > 0;
+ if (has_poly || has_edge) {
+ surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh");
- if (surmd->mesh->totpoly) {
- BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_LOOPTRI, 2);
- }
- else {
- BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_EDGES, 2);
+ if (has_poly) {
+ BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_LOOPTRI, 2);
+ }
+ else if (has_edge) {
+ BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_EDGES, 2);
+ }
}
}
}
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 9d21ff19f46..24085b31fc3 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -178,6 +178,7 @@ set(SRC
geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
geometry/nodes/node_geo_mesh_primitive_line.cc
geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+ geometry/nodes/node_geo_mesh_to_curve.cc
geometry/nodes/node_geo_object_info.cc
geometry/nodes/node_geo_point_distribute.cc
geometry/nodes/node_geo_point_instance.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index d2a702c30a6..eadfed26be1 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -66,6 +66,7 @@ void register_node_type_geo_mesh_primitive_grid(void);
void register_node_type_geo_mesh_primitive_ico_sphere(void);
void register_node_type_geo_mesh_primitive_line(void);
void register_node_type_geo_mesh_primitive_uv_sphere(void);
+void register_node_type_geo_mesh_to_curve(void);
void register_node_type_geo_object_info(void);
void register_node_type_geo_point_distribute(void);
void register_node_type_geo_point_instance(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index ce1813fdac3..ef5f25e7b57 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -305,6 +305,7 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", Me
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Line", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
+DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
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", "")
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index d9b36924516..dca6dc59ca2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -40,61 +40,74 @@
/** \name Cryptomatte
* \{ */
+static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node_render(
+ const bNode &node, const bool use_meta_data)
+{
+ blender::bke::cryptomatte::CryptomatteSessionPtr session;
+
+ Scene *scene = (Scene *)node.id;
+ if (!scene) {
+ return session;
+ }
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+
+ if (use_meta_data) {
+ Render *render = (scene) ? RE_GetSceneRender(scene) : nullptr;
+ RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr;
+ if (render_result) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_render_result(render_result));
+ }
+ if (render) {
+ RE_ReleaseResult(render);
+ }
+ }
+
+ if (session == nullptr) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_scene(scene));
+ }
+ return session;
+}
+
+static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node_image(
+ const Scene &scene, const bNode &node)
+{
+ blender::bke::cryptomatte::CryptomatteSessionPtr session;
+ Image *image = (Image *)node.id;
+ if (!image) {
+ return session;
+ }
+ BLI_assert(GS(image->id.name) == ID_IM);
+
+ NodeCryptomatte *node_cryptomatte = static_cast<NodeCryptomatte *>(node.storage);
+ ImageUser *iuser = &node_cryptomatte->iuser;
+ BKE_image_user_frame_calc(image, iuser, scene.r.cfra);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
+ RenderResult *render_result = image->rr;
+ if (render_result) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_render_result(render_result));
+ }
+ BKE_image_release_ibuf(image, ibuf, nullptr);
+ return session;
+}
static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node(
- const bNode &node, const int frame_number, const bool use_meta_data)
+ const Scene &scene, const bNode &node, const bool use_meta_data)
{
blender::bke::cryptomatte::CryptomatteSessionPtr session;
if (node.type != CMP_NODE_CRYPTOMATTE) {
return session;
}
- NodeCryptomatte *node_cryptomatte = static_cast<NodeCryptomatte *>(node.storage);
switch (node.custom1) {
case CMP_CRYPTOMATTE_SRC_RENDER: {
- Scene *scene = (Scene *)node.id;
- if (!scene) {
- return session;
- }
- BLI_assert(GS(scene->id.name) == ID_SCE);
-
- if (use_meta_data) {
- Render *render = (scene) ? RE_GetSceneRender(scene) : nullptr;
- RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr;
- if (render_result) {
- session = blender::bke::cryptomatte::CryptomatteSessionPtr(
- BKE_cryptomatte_init_from_render_result(render_result));
- }
- if (render) {
- RE_ReleaseResult(render);
- }
- }
-
- if (session == nullptr) {
- session = blender::bke::cryptomatte::CryptomatteSessionPtr(
- BKE_cryptomatte_init_from_scene(scene));
- }
-
- break;
+ return cryptomatte_init_from_node_render(node, use_meta_data);
}
case CMP_CRYPTOMATTE_SRC_IMAGE: {
- Image *image = (Image *)node.id;
- if (!image) {
- break;
- }
- BLI_assert(GS(image->id.name) == ID_IM);
-
- ImageUser *iuser = &node_cryptomatte->iuser;
- BKE_image_user_frame_calc(image, iuser, frame_number);
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
- RenderResult *render_result = image->rr;
- if (render_result) {
- session = blender::bke::cryptomatte::CryptomatteSessionPtr(
- BKE_cryptomatte_init_from_render_result(render_result));
- }
- BKE_image_release_ibuf(image, ibuf, nullptr);
- break;
+ return cryptomatte_init_from_node_image(scene, node);
}
}
return session;
@@ -111,7 +124,10 @@ static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encode
return nullptr;
}
-static void cryptomatte_add(bNode &node, NodeCryptomatte &node_cryptomatte, float encoded_hash)
+static void cryptomatte_add(const Scene &scene,
+ bNode &node,
+ NodeCryptomatte &node_cryptomatte,
+ float encoded_hash)
{
/* Check if entry already exist. */
if (cryptomatte_find(node_cryptomatte, encoded_hash)) {
@@ -121,9 +137,8 @@ static void cryptomatte_add(bNode &node, NodeCryptomatte &node_cryptomatte, floa
CryptomatteEntry *entry = static_cast<CryptomatteEntry *>(
MEM_callocN(sizeof(CryptomatteEntry), __func__));
entry->encoded_hash = encoded_hash;
- /* TODO(jbakker): Get current frame from scene. */
blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
- node, 0, true);
+ scene, node, true);
if (session) {
BKE_cryptomatte_find_name(session.get(), encoded_hash, entry->name, sizeof(entry->name));
}
@@ -151,12 +166,12 @@ static bNodeSocketTemplate cmp_node_cryptomatte_out[] = {
{-1, ""},
};
-void ntreeCompositCryptomatteSyncFromAdd(bNode *node)
+void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node)
{
BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
if (n->runtime.add[0] != 0.0f) {
- cryptomatte_add(*node, *n, n->runtime.add[0]);
+ cryptomatte_add(*scene, *node, *n, n->runtime.add[0]);
zero_v3(n->runtime.add);
}
}
@@ -170,14 +185,14 @@ void ntreeCompositCryptomatteSyncFromRemove(bNode *node)
zero_v3(n->runtime.remove);
}
}
-void ntreeCompositCryptomatteUpdateLayerNames(bNode *node)
+void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node)
{
BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
BLI_freelistN(&n->runtime.layers);
blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
- *node, 0, false);
+ *scene, *node, false);
if (session) {
for (blender::StringRef layer_name :
@@ -190,12 +205,15 @@ void ntreeCompositCryptomatteUpdateLayerNames(bNode *node)
}
}
-void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len)
+void ntreeCompositCryptomatteLayerPrefix(const Scene *scene,
+ const bNode *node,
+ char *r_prefix,
+ size_t prefix_len)
{
BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
NodeCryptomatte *node_cryptomatte = (NodeCryptomatte *)node->storage;
blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
- *node, 0, false);
+ *scene, *node, false);
std::string first_layer_name;
if (session) {
@@ -216,10 +234,10 @@ void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size
BLI_strncpy(r_prefix, cstr, prefix_len);
}
-CryptomatteSession *ntreeCompositCryptomatteSession(bNode *node)
+CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node)
{
blender::bke::cryptomatte::CryptomatteSessionPtr session_ptr = cryptomatte_init_from_node(
- *node, 0, true);
+ *scene, *node, true);
return session_ptr.release();
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
new file mode 100644
index 00000000000..b852f929b5f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -0,0 +1,318 @@
+/*
+ * 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 "BLI_array.hh"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+using blender::Array;
+
+static bNodeSocketTemplate geo_node_mesh_to_curve_in[] = {
+ {SOCK_GEOMETRY, N_("Mesh")},
+ {SOCK_STRING, N_("Selection")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_to_curve_out[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+template<typename T>
+static void copy_attribute_to_points(const VArray<T> &source_data,
+ Span<int> map,
+ MutableSpan<T> dest_data)
+{
+ for (const int point_index : map.index_range()) {
+ const int vert_index = map[point_index];
+ dest_data[point_index] = source_data[vert_index];
+ }
+}
+
+static void copy_attributes_to_points(CurveEval &curve,
+ const MeshComponent &mesh_component,
+ Span<Vector<int>> point_to_vert_maps)
+{
+ MutableSpan<SplinePtr> splines = curve.splines();
+ Set<std::string> source_attribute_names = mesh_component.attribute_names();
+
+ /* Copy builtin control point attributes. */
+ if (source_attribute_names.contains_as("tilt")) {
+ const GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
+ "tilt", ATTR_DOMAIN_POINT, 0.0f);
+ parallel_for(splines.index_range(), 256, [&](IndexRange range) {
+ for (const int i : range) {
+ copy_attribute_to_points<float>(
+ *tilt_attribute, point_to_vert_maps[i], splines[i]->tilts());
+ }
+ });
+ source_attribute_names.remove_contained_as("tilt");
+ }
+ if (source_attribute_names.contains_as("radius")) {
+ const GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
+ "radius", ATTR_DOMAIN_POINT, 1.0f);
+ parallel_for(splines.index_range(), 256, [&](IndexRange range) {
+ for (const int i : range) {
+ copy_attribute_to_points<float>(
+ *radius_attribute, point_to_vert_maps[i], splines[i]->radii());
+ }
+ });
+ source_attribute_names.remove_contained_as("radius");
+ }
+
+ /* Don't copy other builtin control point attributes. */
+ source_attribute_names.remove_as("position");
+
+ /* Copy dynamic control point attributes. */
+ for (const StringRef name : source_attribute_names) {
+ const GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read(name,
+ ATTR_DOMAIN_POINT);
+ /* Some attributes might not exist if they were builtin attribute on domains that don't
+ * have any elements, i.e. a face attribute on the output of the line primitive node. */
+ if (!mesh_attribute) {
+ continue;
+ }
+
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute->type());
+
+ parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ /* Create attribute on the spline points. */
+ splines[i]->attributes.create(name, data_type);
+ std::optional<GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(name);
+ BLI_assert(spline_attribute);
+
+ /* Copy attribute based on the map for this spline. */
+ attribute_math::convert_to_static_type(mesh_attribute->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_attribute_to_points<T>(
+ mesh_attribute->typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>());
+ });
+ }
+ });
+ }
+
+ curve.assert_valid_point_attributes();
+}
+
+struct CurveFromEdgesOutput {
+ std::unique_ptr<CurveEval> curve;
+ Vector<Vector<int>> point_to_vert_maps;
+};
+
+static CurveFromEdgesOutput mesh_to_curve(Span<MVert> verts, Span<std::pair<int, int>> edges)
+{
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ Vector<Vector<int>> point_to_vert_maps;
+
+ /* Compute the number of edges connecting to each vertex. */
+ Array<int> neighbor_count(verts.size(), 0);
+ for (const std::pair<int, int> &edge : edges) {
+ neighbor_count[edge.first]++;
+ neighbor_count[edge.second]++;
+ }
+
+ /* Compute an offset into the array of neighbor edges based on the counts. */
+ Array<int> neighbor_offsets(verts.size());
+ int start = 0;
+ for (const int i : verts.index_range()) {
+ neighbor_offsets[i] = start;
+ start += neighbor_count[i];
+ }
+
+ /* Use as an index into the "neighbor group" for each vertex. */
+ Array<int> used_slots(verts.size(), 0);
+ /* Calculate the indices of each vertex's neighboring edges. */
+ Array<int> neighbors(edges.size() * 2);
+ for (const int i : edges.index_range()) {
+ const int v1 = edges[i].first;
+ const int v2 = edges[i].second;
+ neighbors[neighbor_offsets[v1] + used_slots[v1]] = v2;
+ neighbors[neighbor_offsets[v2] + used_slots[v2]] = v1;
+ used_slots[v1]++;
+ used_slots[v2]++;
+ }
+
+ /* Now use the neighbor group offsets calculated above as a count used edges at each vertex. */
+ Array<int> unused_edges = std::move(used_slots);
+
+ for (const int start_vert : verts.index_range()) {
+ /* The vertex will be part of a cyclic spline. */
+ if (neighbor_count[start_vert] == 2) {
+ continue;
+ }
+
+ /* The vertex has no connected edges, or they were already used. */
+ if (unused_edges[start_vert] == 0) {
+ continue;
+ }
+
+ for (const int i : IndexRange(neighbor_count[start_vert])) {
+ int current_vert = start_vert;
+ int next_vert = neighbors[neighbor_offsets[current_vert] + i];
+
+ if (unused_edges[next_vert] == 0) {
+ continue;
+ }
+
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ Vector<int> point_to_vert_map;
+
+ spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
+ point_to_vert_map.append(current_vert);
+
+ /* Follow connected edges until we read a vertex with more than two connected edges. */
+ while (true) {
+ int last_vert = current_vert;
+ current_vert = next_vert;
+
+ spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
+ point_to_vert_map.append(current_vert);
+ unused_edges[current_vert]--;
+ unused_edges[last_vert]--;
+
+ if (neighbor_count[current_vert] != 2) {
+ break;
+ }
+
+ const int offset = neighbor_offsets[current_vert];
+ const int next_a = neighbors[offset];
+ const int next_b = neighbors[offset + 1];
+ next_vert = (last_vert == next_a) ? next_b : next_a;
+ }
+
+ spline->attributes.reallocate(spline->size());
+ curve->add_spline(std::move(spline));
+ point_to_vert_maps.append(std::move(point_to_vert_map));
+ }
+ }
+
+ /* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
+ for (const int start_vert : verts.index_range()) {
+ if (unused_edges[start_vert] != 2) {
+ continue;
+ }
+
+ int current_vert = start_vert;
+ int next_vert = neighbors[neighbor_offsets[current_vert]];
+
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ Vector<int> point_to_vert_map;
+ spline->set_cyclic(true);
+
+ spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
+ point_to_vert_map.append(current_vert);
+
+ /* Follow connected edges until we loop back to the start vertex. */
+ while (next_vert != start_vert) {
+ const int last_vert = current_vert;
+ current_vert = next_vert;
+
+ spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
+ point_to_vert_map.append(current_vert);
+ unused_edges[current_vert]--;
+ unused_edges[last_vert]--;
+
+ const int offset = neighbor_offsets[current_vert];
+ const int next_a = neighbors[offset];
+ const int next_b = neighbors[offset + 1];
+ next_vert = (last_vert == next_a) ? next_b : next_a;
+ }
+
+ spline->attributes.reallocate(spline->size());
+ curve->add_spline(std::move(spline));
+ point_to_vert_maps.append(std::move(point_to_vert_map));
+ }
+
+ curve->attributes.reallocate(curve->splines().size());
+ return {std::move(curve), std::move(point_to_vert_maps)};
+}
+
+/**
+ * Get a separate array of the indices for edges in a selection (a boolean attribute).
+ * This helps to make the above algorithm simpler by removing the need to check for selection
+ * in many places.
+ */
+static Vector<std::pair<int, int>> get_selected_edges(GeoNodeExecParams params,
+ const MeshComponent &component)
+{
+ const Mesh &mesh = *component.get_for_read();
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ if (!selection_name.empty() && !component.attribute_exists(selection_name)) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("No attribute with name \"") + selection_name + "\"");
+ }
+ GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>(
+ selection_name, ATTR_DOMAIN_EDGE, true);
+
+ Vector<std::pair<int, int>> selected_edges;
+ for (const int i : IndexRange(mesh.totedge)) {
+ if (selection[i]) {
+ selected_edges.append({mesh.medge[i].v1, mesh.medge[i].v2});
+ }
+ }
+
+ return selected_edges;
+}
+
+static void geo_node_mesh_to_curve_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ if (!geometry_set.has_mesh()) {
+ params.set_output("Curve", GeometrySet());
+ return;
+ }
+
+ const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *component.get_for_read();
+ Span<MVert> verts = Span{mesh.mvert, mesh.totvert};
+ Span<MEdge> edges = Span{mesh.medge, mesh.totedge};
+ if (edges.size() == 0) {
+ params.set_output("Curve", GeometrySet());
+ return;
+ }
+
+ Vector<std::pair<int, int>> selected_edges = get_selected_edges(params, component);
+
+ CurveFromEdgesOutput output = mesh_to_curve(verts, selected_edges);
+ copy_attributes_to_points(*output.curve, component, output.point_to_vert_maps);
+
+ params.set_output("Curve", GeometrySet::create_with_curve(output.curve.release()));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_to_curve()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_mesh_to_curve_in, geo_node_mesh_to_curve_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_curve_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index 049ba5d3143..742fafba9e6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -22,24 +22,24 @@
static bNodeSocketTemplate geo_node_switch_in[] = {
{SOCK_BOOLEAN, N_("Switch")},
- {SOCK_FLOAT, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
- {SOCK_FLOAT, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
- {SOCK_INT, N_("A"), 0, 0, 0, 0, -100000, 100000},
- {SOCK_INT, N_("B"), 0, 0, 0, 0, -100000, 100000},
- {SOCK_BOOLEAN, N_("A")},
- {SOCK_BOOLEAN, N_("B")},
- {SOCK_VECTOR, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
- {SOCK_VECTOR, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
- {SOCK_RGBA, N_("A"), 0.8, 0.8, 0.8, 1.0},
- {SOCK_RGBA, N_("B"), 0.8, 0.8, 0.8, 1.0},
- {SOCK_STRING, N_("A")},
- {SOCK_STRING, N_("B")},
- {SOCK_GEOMETRY, N_("A")},
- {SOCK_GEOMETRY, N_("B")},
- {SOCK_OBJECT, N_("A")},
- {SOCK_OBJECT, N_("B")},
- {SOCK_COLLECTION, N_("A")},
- {SOCK_COLLECTION, N_("B")},
+ {SOCK_FLOAT, N_("False"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_FLOAT, N_("True"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_INT, N_("False"), 0, 0, 0, 0, -100000, 100000},
+ {SOCK_INT, N_("True"), 0, 0, 0, 0, -100000, 100000},
+ {SOCK_BOOLEAN, N_("False")},
+ {SOCK_BOOLEAN, N_("True")},
+ {SOCK_VECTOR, N_("False"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_VECTOR, N_("True"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_RGBA, N_("False"), 0.8, 0.8, 0.8, 1.0},
+ {SOCK_RGBA, N_("True"), 0.8, 0.8, 0.8, 1.0},
+ {SOCK_STRING, N_("False")},
+ {SOCK_STRING, N_("True")},
+ {SOCK_GEOMETRY, N_("False")},
+ {SOCK_GEOMETRY, N_("True")},
+ {SOCK_OBJECT, N_("False")},
+ {SOCK_OBJECT, N_("True")},
+ {SOCK_COLLECTION, N_("False")},
+ {SOCK_COLLECTION, N_("True")},
{-1, ""},
};
@@ -64,7 +64,7 @@ static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), Pointe
static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
- data->input_type = SOCK_FLOAT;
+ data->input_type = SOCK_GEOMETRY;
node->storage = data;
}
@@ -91,8 +91,8 @@ static void output_input(GeoNodeExecParams &params,
const StringRef input_suffix,
const StringRef output_identifier)
{
- const std::string name_a = "A" + input_suffix;
- const std::string name_b = "B" + input_suffix;
+ const std::string name_a = "False" + input_suffix;
+ const std::string name_b = "True" + input_suffix;
if (input) {
params.set_input_unused(name_a);
if (params.lazy_require_input(name_b)) {
@@ -165,7 +165,7 @@ void register_node_type_geo_switch()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, geo_node_switch_in, geo_node_switch_out);
node_type_init(&ntype, geo_node_switch_init);
node_type_update(&ntype, blender::nodes::geo_node_switch_update);
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index f1a8d450ea5..598640f8f68 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1385,7 +1385,6 @@ static PyObject *bpy_bmesh_calc_loop_triangles(BPy_BMElem *self)
BMesh *bm;
int looptris_tot;
- int tottri;
BMLoop *(*looptris)[3];
PyObject *ret;
@@ -1398,10 +1397,10 @@ static PyObject *bpy_bmesh_calc_loop_triangles(BPy_BMElem *self)
looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
looptris = PyMem_MALLOC(sizeof(*looptris) * looptris_tot);
- BM_mesh_calc_tessellation(bm, looptris, &tottri);
+ BM_mesh_calc_tessellation(bm, looptris);
- ret = PyList_New(tottri);
- for (i = 0; i < tottri; i++) {
+ ret = PyList_New(looptris_tot);
+ for (i = 0; i < looptris_tot; i++) {
PyList_SET_ITEM(ret, i, BPy_BMLoop_Array_As_Tuple(bm, looptris[i], 3));
}
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 927ec11c376..4de6063098b 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -82,7 +82,10 @@ static PyTypeObject BlenderAppType;
static PyStructSequence_Field app_info_fields[] = {
{"version", "The Blender version as a tuple of 3 numbers. eg. (2, 83, 1)"},
- {"version_file", "The blend file version, compatible with ``bpy.data.version``"},
+ {"version_file",
+ "The Blender version, as a tuple, last used to save a .blend file, compatible with "
+ "``bpy.data.version``. This value should be used for handling compatibility changes between "
+ "Blender versions"},
{"version_string", "The Blender version formatted as a string"},
{"version_cycle", "The release status of this build alpha/beta/rc/release"},
{"version_char", "Deprecated, always an empty string"},
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index 1acbcc006ca..79ed9e68420 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -961,8 +961,6 @@ static PyObject *C_BVHTree_FromBMesh(PyObject *UNUSED(cls), PyObject *args, PyOb
/* Get data for tessellation */
{
- int tris_len_dummy;
-
coords_len = (uint)bm->totvert;
tris_len = (uint)poly_to_tri_count(bm->totface, bm->totloop);
@@ -971,8 +969,7 @@ static PyObject *C_BVHTree_FromBMesh(PyObject *UNUSED(cls), PyObject *args, PyOb
looptris = MEM_mallocN(sizeof(*looptris) * (size_t)tris_len, __func__);
- BM_mesh_calc_tessellation(bm, looptris, &tris_len_dummy);
- BLI_assert(tris_len_dummy == (int)tris_len);
+ BM_mesh_calc_tessellation(bm, looptris);
}
{
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index a0c95c1c197..5ccf2a027b0 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -518,7 +518,7 @@ static size_t inflate_file_to_imbuf(ImBuf *ibuf, FILE *file, DiskCacheHeaderEntr
static bool seq_disk_cache_read_header(FILE *file, DiskCacheHeader *header)
{
- fseek(file, 0, 0);
+ BLI_fseek(file, 0LL, SEEK_SET);
const size_t num_items_read = fread(header, sizeof(*header), 1, file);
if (num_items_read < 1) {
BLI_assert(!"unable to read disk cache header");
@@ -540,7 +540,7 @@ static bool seq_disk_cache_read_header(FILE *file, DiskCacheHeader *header)
static size_t seq_disk_cache_write_header(FILE *file, DiskCacheHeader *header)
{
- fseek(file, 0, 0);
+ BLI_fseek(file, 0LL, SEEK_SET);
return fwrite(header, sizeof(*header), 1, file);
}
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index d881c90a1e0..8ed769880a4 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -1237,6 +1237,12 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
}
if (*r_is_proxy_image == false) {
+ if (sanim && sanim->anim) {
+ short fps_denom;
+ float fps_num;
+ IMB_anim_get_fps(sanim->anim, &fps_denom, &fps_num, true);
+ seq->strip->stripdata->orig_fps = fps_denom / fps_num;
+ }
seq->strip->stripdata->orig_width = ibuf->x;
seq->strip->stripdata->orig_height = ibuf->y;
}
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index 5ec2269b993..64671aeb265 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -548,15 +548,25 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+ float video_fps = 0.0f;
+
if (anim_arr[0] != NULL) {
seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
IMB_anim_load_metadata(anim_arr[0]);
+ short fps_denom;
+ float fps_num;
+
+ IMB_anim_get_fps(anim_arr[0], &fps_denom, &fps_num, true);
+
+ video_fps = fps_denom / fps_num;
+
/* Adjust scene's frame rate settings to match. */
if (load_data->flags & SEQ_LOAD_MOVIE_SYNC_FPS) {
- IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true);
+ scene->r.frs_sec = fps_denom;
+ scene->r.frs_sec_base = fps_num;
}
/* Set initial scale based on load_data->fit_method. */
@@ -577,6 +587,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
strip->stripdata->orig_width = orig_width;
strip->stripdata->orig_height = orig_height;
+ strip->stripdata->orig_fps = video_fps;
BLI_split_dirfile(load_data->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
seq_add_set_view_transform(scene, seq, load_data);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 611a9cba000..2ffa04bd8ae 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -620,7 +620,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
struct GPUMatrixUnproject_Precalc unproj_precalc;
GPU_matrix_unproject_precalc(&unproj_precalc, rv3d->viewmat, rv3d->winmat, viewport);
- GPU_matrix_unproject_with_precalc(&unproj_precalc, co_screen, co_3d_origin);
+ GPU_matrix_unproject_3fv_with_precalc(&unproj_precalc, co_screen, co_3d_origin);
uint *buf_iter = buffer;
int hit_found = -1;
@@ -631,7 +631,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
wmGizmo *gz = visible_gizmos[buf_iter[3] >> 8];
float co_3d[3];
co_screen[2] = int_as_float(buf_iter[1]);
- GPU_matrix_unproject_with_precalc(&unproj_precalc, co_screen, co_3d);
+ GPU_matrix_unproject_3fv_with_precalc(&unproj_precalc, co_screen, co_3d);
float select_bias = gz->select_bias;
if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) {
select_bias *= gz->scale_final;
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 6a768106d9e..92cc4ae297a 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -119,6 +119,10 @@ if(WITH_GMP)
add_definitions(-DWITH_GMP)
endif()
+if(WITH_OPENCOLORIO)
+ add_definitions(-DWITH_OCIO)
+endif()
+
# Setup the exe sources and buildinfo
set(SRC
creator.c
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 36fdaef507b..8b1ac05f086 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -674,6 +674,9 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
printf(" $BLENDER_USER_DATAFILES Directory for user data files (icons, translations, ..).\n");
printf(" $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n");
printf(" $BLENDER_SYSTEM_PYTHON Directory for system Python libraries.\n");
+# ifdef WITH_OCIO
+ printf(" $OCIO Path to override the OpenColorIO config file.\n");
+# endif
# ifdef WIN32
printf(" $TEMP Store temporary files here.\n");
# else
diff --git a/source/tools b/source/tools
-Subproject f99d29ae3e6ad44d45d79309454c45f8088781a
+Subproject 01f51a0e551ab730f0934dc6488613690ac4bf8