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:
-rw-r--r--build_files/build_environment/cmake/download.cmake2
-rw-r--r--build_files/cmake/Modules/FindUSD.cmake1
-rw-r--r--build_files/cmake/Modules/FindWebP.cmake5
-rw-r--r--build_files/cmake/platform/platform_win32.cmake2
-rw-r--r--build_files/config/pipeline_config.yaml18
-rw-r--r--doc/doxygen/Doxyfile2
-rw-r--r--intern/cycles/blender/shader.cpp12
-rw-r--r--intern/cycles/device/optix/device_impl.cpp37
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/osl/shaders/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/osl/shaders/node_color.h50
-rw-r--r--intern/cycles/kernel/osl/shaders/node_combine_color.osl16
-rw-r--r--intern/cycles/kernel/osl/shaders/node_separate_color.osl26
-rw-r--r--intern/cycles/kernel/svm/color_util.h26
-rw-r--r--intern/cycles/kernel/svm/sepcomb_color.h54
-rw-r--r--intern/cycles/kernel/svm/svm.h7
-rw-r--r--intern/cycles/kernel/svm/types.h8
-rw-r--r--intern/cycles/scene/shader_nodes.cpp121
-rw-r--r--intern/cycles/scene/shader_nodes.h20
-rw-r--r--intern/cycles/util/color.h50
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp6
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp25
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h3
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_puff.datbin0 -> 1718 bytes
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/splash.pngbin1113821 -> 842492 bytes
-rw-r--r--release/scripts/modules/bpy_types.py8
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py32
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py23
-rw-r--r--release/scripts/startup/bl_ui/space_image.py28
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py12
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py80
-rw-r--r--release/scripts/startup/nodeitems_builtins.py24
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_curves.hh26
-rw-r--r--source/blender/blenkernel/BKE_geometry_fields.hh10
-rw-r--r--source/blender/blenkernel/BKE_lib_principle_properties.h2
-rw-r--r--source/blender/blenkernel/BKE_modifier.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h36
-rw-r--r--source/blender/blenkernel/BKE_paint.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c1
-rw-r--r--source/blender/blenkernel/intern/curve_nurbs.cc8
-rw-r--r--source/blender/blenkernel/intern/curve_poly.cc4
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc4
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc40
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc63
-rw-r--r--source/blender/blenkernel/intern/node.cc8
-rw-r--r--source/blender/blenkernel/intern/object.cc2
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c20
-rw-r--r--source/blender/blenkernel/intern/tracking_plane_tracker.c6
-rw-r--r--source/blender/blenlib/CMakeLists.txt4
-rw-r--r--source/blender/blenlib/intern/math_color.c2
-rw-r--r--source/blender/blenloader/intern/readfile.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c262
-rw-r--r--source/blender/bmesh/bmesh_class.h16
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc24
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.cc59
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.h39
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc78
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h56
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.cc59
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.h39
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc110
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h56
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cc62
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.h20
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_defines.hh8
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.cc4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_material.hh6
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.cc10
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader_shared.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.cc10
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.hh4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_world.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c2
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/extra_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/volume_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh2
-rw-r--r--source/blender/draw/engines/select/shaders/infos/select_id_info.hh2
-rw-r--r--source/blender/draw/intern/draw_subdivision.h4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc2
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c5
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c5
-rw-r--r--source/blender/editors/curve/CMakeLists.txt2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt1
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc12
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c166
-rw-r--r--source/blender/editors/include/ED_uvedit.h12
-rw-r--r--source/blender/editors/include/ED_view3d.h16
-rw-r--r--source/blender/editors/include/UI_interface.h2
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.cc7
-rw-r--r--source/blender/editors/io/io_alembic.c3
-rw-r--r--source/blender/editors/object/object_constraint.c4
-rw-r--r--source/blender/editors/object/object_modes.c7
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc91
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_brush.cc (renamed from source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc)33
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc47
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc133
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc166
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh4
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc20
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc41
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc8
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c1
-rw-r--r--source/blender/editors/space_node/drawnode.cc40
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc6
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c1
-rw-r--r--source/blender/editors/transform/transform_snap.c58
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c33
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt17
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c17
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h12
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc25
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c895
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h10
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/metal/mtl_texture.hh2
-rw-r--r--source/blender/gpu/metal/mtl_texture.mm6
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl50
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl28
-rw-r--r--source/blender/imbuf/IMB_imbuf.h8
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h17
-rw-r--r--source/blender/imbuf/intern/filetype.c16
-rw-r--r--source/blender/imbuf/intern/jpeg.c117
-rw-r--r--source/blender/imbuf/intern/readimage.c57
-rw-r--r--source/blender/imbuf/intern/thumbs.c55
-rw-r--r--source/blender/io/wavefront_obj/CMakeLists.txt1
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc4
-rw-r--r--source/blender/makesdna/DNA_anim_types.h6
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h6
-rw-r--r--source/blender/makesdna/DNA_brush_types.h2
-rw-r--r--source/blender/makesdna/DNA_curves_types.h21
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h8
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h6
-rw-r--r--source/blender/makesdna/DNA_layer_types.h2
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h15
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h2
-rw-r--r--source/blender/makesdna/DNA_modifier_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h10
-rw-r--r--source/blender/makesdna/DNA_node_types.h27
-rw-r--r--source/blender/makesdna/DNA_object_types.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h10
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h4
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h2
-rw-r--r--source/blender/makesrna/RNA_enum_items.h2
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c16
-rw-r--r--source/blender/makesrna/intern/rna_brush.c25
-rw-r--r--source/blender/makesrna/intern/rna_curves.c16
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c17
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c75
-rw-r--r--source/blender/makesrna/intern/rna_space.c11
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c16
-rw-r--r--source/blender/makesrna/intern/rna_wm.c6
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c74
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/NOD_function.h2
-rw-r--r--source/blender/nodes/NOD_shader.h2
-rw-r--r--source/blender/nodes/NOD_static_types.h38
-rw-r--r--source/blender/nodes/NOD_texture.h2
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc139
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc4
-rw-r--r--source/blender/nodes/function/CMakeLists.txt2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_combine_color.cc108
-rw-r--r--source/blender/nodes/function/nodes/node_fn_separate_color.cc205
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc51
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc73
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc40
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc98
-rw-r--r--source/blender/nodes/intern/node_util.c33
-rw-r--r--source/blender/nodes/intern/node_util.h1
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc162
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc4
-rw-r--r--source/blender/nodes/texture/CMakeLists.txt2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_combine_color.c76
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_decompose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_separate_color.c102
-rw-r--r--source/blender/python/gpu/CMakeLists.txt2
-rw-r--r--source/blender/windowmanager/WM_types.h5
205 files changed, 4636 insertions, 1225 deletions
diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake
index 92dea453133..80c53d05c28 100644
--- a/build_files/build_environment/cmake/download.cmake
+++ b/build_files/build_environment/cmake/download.cmake
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
## Update and uncomment this in the release branch
-set(BLENDER_VERSION 3.2)
+# set(BLENDER_VERSION 3.1)
function(download_source dep)
set(TARGET_FILE ${${dep}_FILE})
diff --git a/build_files/cmake/Modules/FindUSD.cmake b/build_files/cmake/Modules/FindUSD.cmake
index d8f2ee22e6e..0fd5f06bb35 100644
--- a/build_files/cmake/Modules/FindUSD.cmake
+++ b/build_files/cmake/Modules/FindUSD.cmake
@@ -64,6 +64,7 @@ ENDIF()
MARK_AS_ADVANCED(
USD_INCLUDE_DIR
USD_LIBRARY_DIR
+ USD_LIBRARY
)
UNSET(_usd_SEARCH_DIRS)
diff --git a/build_files/cmake/Modules/FindWebP.cmake b/build_files/cmake/Modules/FindWebP.cmake
index 741c48ec447..2d8923a7fe6 100644
--- a/build_files/cmake/Modules/FindWebP.cmake
+++ b/build_files/cmake/Modules/FindWebP.cmake
@@ -74,4 +74,9 @@ ENDIF()
MARK_AS_ADVANCED(
WEBP_INCLUDE_DIR
WEBP_LIBRARY_DIR
+
+ # Generated names.
+ WEBP_WEBPDEMUX_LIBRARY
+ WEBP_WEBPMUX_LIBRARY
+ WEBP_WEBP_LIBRARY
)
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index c5d2049b292..40c25abd585 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -104,7 +104,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 Shcore
+ pathcch Shcore Dwmapi
)
if(WITH_INPUT_IME)
diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml
index d1f1fe78d21..8222f2ff0b9 100644
--- a/build_files/config/pipeline_config.yaml
+++ b/build_files/config/pipeline_config.yaml
@@ -5,38 +5,38 @@
update-code:
git:
submodules:
- - branch: blender-v3.2-release
+ - branch: master
commit_id: HEAD
path: release/scripts/addons
- - branch: blender-v3.2-release
+ - branch: master
commit_id: HEAD
path: release/scripts/addons_contrib
- - branch: blender-v3.2-release
+ - branch: master
commit_id: HEAD
path: release/datafiles/locale
- - branch: blender-v3.2-release
+ - branch: master
commit_id: HEAD
path: source/tools
svn:
libraries:
darwin-arm64:
- branch: tags/blender-3.2-release
+ branch: trunk
commit_id: HEAD
path: lib/darwin_arm64
darwin-x86_64:
- branch: tags/blender-3.2-release
+ branch: trunk
commit_id: HEAD
path: lib/darwin
linux-x86_64:
- branch: tags/blender-3.2-release
+ branch: trunk
commit_id: HEAD
path: lib/linux_centos7_x86_64
windows-amd64:
- branch: tags/blender-3.2-release
+ branch: trunk
commit_id: HEAD
path: lib/win64_vc15
tests:
- branch: tags/blender-3.2-release
+ branch: trunk
commit_id: HEAD
path: lib/tests
benchmarks:
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index b8f54f548b4..0176a888377 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = V3.2
+PROJECT_NUMBER = V3.3
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index d3527567b96..35c98a71558 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -355,6 +355,18 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
node = graph->create_node<CombineHSVNode>();
}
+ else if (b_node.is_a(&RNA_ShaderNodeSeparateColor)) {
+ BL::ShaderNodeSeparateColor b_separate_node(b_node);
+ SeparateColorNode *separate_node = graph->create_node<SeparateColorNode>();
+ separate_node->set_color_type((NodeCombSepColorType)b_separate_node.mode());
+ node = separate_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeCombineColor)) {
+ BL::ShaderNodeCombineColor b_combine_node(b_node);
+ CombineColorNode *combine_node = graph->create_node<CombineColorNode>();
+ combine_node->set_color_type((NodeCombSepColorType)b_combine_node.mode());
+ node = combine_node;
+ }
else if (b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
node = graph->create_node<SeparateXYZNode>();
}
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index 8830d8c44ac..6329144131e 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -23,6 +23,7 @@
# include "util/md5.h"
# include "util/path.h"
# include "util/progress.h"
+# include "util/task.h"
# include "util/time.h"
# undef __KERNEL_CPU__
@@ -216,6 +217,24 @@ static OptixResult optixUtilDenoiserInvokeTiled(OptixDenoiser denoiser,
return OPTIX_SUCCESS;
}
+# if OPTIX_ABI_VERSION >= 55
+static void execute_optix_task(TaskPool &pool, OptixTask task, OptixResult &failure_reason)
+{
+ OptixTask additional_tasks[16];
+ unsigned int num_additional_tasks = 0;
+
+ const OptixResult result = optixTaskExecute(task, additional_tasks, 16, &num_additional_tasks);
+ if (result == OPTIX_SUCCESS) {
+ for (unsigned int i = 0; i < num_additional_tasks; ++i) {
+ pool.push(function_bind(&execute_optix_task, std::ref(pool), additional_tasks[i], std::ref(failure_reason)));
+ }
+ }
+ else {
+ failure_reason = result;
+ }
+}
+# endif
+
} // namespace
OptiXDevice::Denoiser::Denoiser(OptiXDevice *device)
@@ -453,6 +472,23 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
return false;
}
+# if OPTIX_ABI_VERSION >= 55
+ OptixTask task = nullptr;
+ OptixResult result = optixModuleCreateFromPTXWithTasks(context,
+ &module_options,
+ &pipeline_options,
+ ptx_data.data(),
+ ptx_data.size(),
+ nullptr,
+ nullptr,
+ &optix_module,
+ &task);
+ if (result == OPTIX_SUCCESS) {
+ TaskPool pool;
+ execute_optix_task(pool, task, result);
+ pool.wait_work();
+ }
+# else
const OptixResult result = optixModuleCreateFromPTX(context,
&module_options,
&pipeline_options,
@@ -461,6 +497,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
nullptr,
0,
&optix_module);
+# endif
if (result != OPTIX_SUCCESS) {
set_error(string_printf("Failed to load OptiX kernel from '%s' (%s)",
ptx_filename.c_str(),
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index d97854a52d0..473bdb67920 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -145,6 +145,7 @@ set(SRC_KERNEL_SVM_HEADERS
svm/normal.h
svm/ramp.h
svm/ramp_util.h
+ svm/sepcomb_color.h
svm/sepcomb_hsv.h
svm/sepcomb_vector.h
svm/sky.h
diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
index 7ced21c5670..741bce7c399 100644
--- a/intern/cycles/kernel/osl/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
@@ -16,6 +16,7 @@ set(SRC_OSL
node_camera.osl
node_checker_texture.osl
node_clamp.osl
+ node_combine_color.osl
node_combine_rgb.osl
node_combine_hsv.osl
node_combine_xyz.osl
@@ -68,6 +69,7 @@ set(SRC_OSL
node_refraction_bsdf.osl
node_rgb_curves.osl
node_rgb_ramp.osl
+ node_separate_color.osl
node_separate_rgb.osl
node_separate_hsv.osl
node_separate_xyz.osl
diff --git a/intern/cycles/kernel/osl/shaders/node_color.h b/intern/cycles/kernel/osl/shaders/node_color.h
index 388dd114e9a..06735f5b03d 100644
--- a/intern/cycles/kernel/osl/shaders/node_color.h
+++ b/intern/cycles/kernel/osl/shaders/node_color.h
@@ -148,3 +148,53 @@ color hsv_to_rgb(color hsv)
return rgb;
}
+
+color rgb_to_hsl(color rgb)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ l = min(1.0, (cmax + cmin) / 2.0);
+
+ if (cmax == cmin) {
+ h = s = 0.0; /* achromatic */
+ }
+ else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5 ? cdelta / (2.0 - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb[0]) {
+ h = (rgb[1] - rgb[2]) / cdelta + (rgb[1] < rgb[2] ? 6.0 : 0.0);
+ }
+ else if (cmax == rgb[1]) {
+ h = (rgb[2] - rgb[0]) / cdelta + 2.0;
+ }
+ else {
+ h = (rgb[0] - rgb[1]) / cdelta + 4.0;
+ }
+ }
+ h /= 6.0;
+
+ return color(h, s, l);
+}
+
+color hsl_to_rgb(color hsl)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl[0];
+ s = hsl[1];
+ l = hsl[2];
+
+ nr = abs(h * 6.0 - 3.0) - 1.0;
+ ng = 2.0 - abs(h * 6.0 - 2.0);
+ nb = 2.0 - abs(h * 6.0 - 4.0);
+
+ nr = clamp(nr, 0.0, 1.0);
+ nb = clamp(nb, 0.0, 1.0);
+ ng = clamp(ng, 0.0, 1.0);
+
+ chroma = (1.0 - abs(2.0 * l - 1.0)) * s;
+
+ return color((nr - 0.5) * chroma + l, (ng - 0.5) * chroma + l, (nb - 0.5) * chroma + l);
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_combine_color.osl b/intern/cycles/kernel/osl/shaders/node_combine_color.osl
new file mode 100644
index 00000000000..681a592d2bb
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_combine_color.osl
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "stdcycles.h"
+
+shader node_combine_color(string color_type = "rgb",
+ float Red = 0.0,
+ float Green = 0.0,
+ float Blue = 0.0,
+ output color Color = 0.8)
+{
+ if (color_type == "rgb" || color_type == "hsv" || color_type == "hsl")
+ Color = color(color_type, Red, Green, Blue);
+ else
+ warning("%s", "Unknown color space!");
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_separate_color.osl b/intern/cycles/kernel/osl/shaders/node_separate_color.osl
new file mode 100644
index 00000000000..6f3e3149d8e
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_separate_color.osl
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "node_color.h"
+#include "stdcycles.h"
+
+shader node_separate_color(string color_type = "rgb",
+ color Color = 0.8,
+ output float Red = 0.0,
+ output float Green = 0.0,
+ output float Blue = 0.0)
+{
+ color col;
+ if (color_type == "rgb")
+ col = Color;
+ else if (color_type == "hsv")
+ col = rgb_to_hsv(Color);
+ else if (color_type == "hsl")
+ col = rgb_to_hsl(Color);
+ else
+ warning("%s", "Unknown color space!");
+
+ Red = col[0];
+ Green = col[1];
+ Blue = col[2];
+}
diff --git a/intern/cycles/kernel/svm/color_util.h b/intern/cycles/kernel/svm/color_util.h
index b439721383c..fa22d4bc8c2 100644
--- a/intern/cycles/kernel/svm/color_util.h
+++ b/intern/cycles/kernel/svm/color_util.h
@@ -307,4 +307,30 @@ ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness,
return color;
}
+ccl_device float3 svm_combine_color(NodeCombSepColorType type, float3 color)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_HSV:
+ return hsv_to_rgb(color);
+ case NODE_COMBSEP_COLOR_HSL:
+ return hsl_to_rgb(color);
+ case NODE_COMBSEP_COLOR_RGB:
+ default:
+ return color;
+ }
+}
+
+ccl_device float3 svm_separate_color(NodeCombSepColorType type, float3 color)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_HSV:
+ return rgb_to_hsv(color);
+ case NODE_COMBSEP_COLOR_HSL:
+ return rgb_to_hsl(color);
+ case NODE_COMBSEP_COLOR_RGB:
+ default:
+ return color;
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/sepcomb_color.h b/intern/cycles/kernel/svm/sepcomb_color.h
new file mode 100644
index 00000000000..d186e7f163b
--- /dev/null
+++ b/intern/cycles/kernel/svm/sepcomb_color.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_combine_color(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint color_type,
+ uint inputs_stack_offsets,
+ uint result_stack_offset)
+{
+ uint red_stack_offset, green_stack_offset, blue_stack_offset;
+ svm_unpack_node_uchar3(
+ inputs_stack_offsets, &red_stack_offset, &green_stack_offset, &blue_stack_offset);
+
+ float r = stack_load_float(stack, red_stack_offset);
+ float g = stack_load_float(stack, green_stack_offset);
+ float b = stack_load_float(stack, blue_stack_offset);
+
+ /* Combine, and convert back to RGB */
+ float3 color = svm_combine_color((NodeCombSepColorType)color_type, make_float3(r, g, b));
+
+ if (stack_valid(result_stack_offset))
+ stack_store_float3(stack, result_stack_offset, color);
+}
+
+ccl_device_noinline void svm_node_separate_color(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint color_type,
+ uint input_stack_offset,
+ uint results_stack_offsets)
+{
+ float3 color = stack_load_float3(stack, input_stack_offset);
+
+ /* Convert color space */
+ color = svm_separate_color((NodeCombSepColorType)color_type, color);
+
+ uint red_stack_offset, green_stack_offset, blue_stack_offset;
+ svm_unpack_node_uchar3(
+ results_stack_offsets, &red_stack_offset, &green_stack_offset, &blue_stack_offset);
+
+ if (stack_valid(red_stack_offset))
+ stack_store_float(stack, red_stack_offset, color.x);
+ if (stack_valid(green_stack_offset))
+ stack_store_float(stack, green_stack_offset, color.y);
+ if (stack_valid(blue_stack_offset))
+ stack_store_float(stack, blue_stack_offset, color.z);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 08352a6231f..5def943c87f 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -181,6 +181,7 @@ CCL_NAMESPACE_END
#include "kernel/svm/noisetex.h"
#include "kernel/svm/normal.h"
#include "kernel/svm/ramp.h"
+#include "kernel/svm/sepcomb_color.h"
#include "kernel/svm/sepcomb_hsv.h"
#include "kernel/svm/sepcomb_vector.h"
#include "kernel/svm/sky.h"
@@ -508,6 +509,12 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
case NODE_MIX:
offset = svm_node_mix(kg, sd, stack, node.y, node.z, node.w, offset);
break;
+ case NODE_SEPARATE_COLOR:
+ svm_node_separate_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_COMBINE_COLOR:
+ svm_node_combine_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
case NODE_SEPARATE_VECTOR:
svm_node_separate_vector(sd, stack, node.y, node.z, node.w);
break;
diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h
index bede58f7a54..82109ec4c4f 100644
--- a/intern/cycles/kernel/svm/types.h
+++ b/intern/cycles/kernel/svm/types.h
@@ -92,6 +92,8 @@ typedef enum ShaderNodeType {
NODE_NORMAL_MAP,
NODE_INVERT,
NODE_MIX,
+ NODE_SEPARATE_COLOR,
+ NODE_COMBINE_COLOR,
NODE_SEPARATE_VECTOR,
NODE_COMBINE_VECTOR,
NODE_SEPARATE_HSV,
@@ -487,6 +489,12 @@ typedef enum NodePrincipledHairParametrization {
NODE_PRINCIPLED_HAIR_NUM,
} NodePrincipledHairParametrization;
+typedef enum NodeCombSepColorType {
+ NODE_COMBSEP_COLOR_RGB,
+ NODE_COMBSEP_COLOR_HSV,
+ NODE_COMBSEP_COLOR_HSL,
+} NodeCombSepColorType;
+
/* Closure */
typedef enum ClosureType {
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index 95fccf725f3..06a2052d4cb 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -5010,6 +5010,63 @@ void MixNode::constant_fold(const ConstantFolder &folder)
}
}
+/* Combine Color */
+
+NODE_DEFINE(CombineColorNode)
+{
+ NodeType *type = NodeType::add("combine_color", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("rgb", NODE_COMBSEP_COLOR_RGB);
+ type_enum.insert("hsv", NODE_COMBSEP_COLOR_HSV);
+ type_enum.insert("hsl", NODE_COMBSEP_COLOR_HSL);
+ SOCKET_ENUM(color_type, "Type", type_enum, NODE_COMBSEP_COLOR_RGB);
+
+ SOCKET_IN_FLOAT(r, "Red", 0.0f);
+ SOCKET_IN_FLOAT(g, "Green", 0.0f);
+ SOCKET_IN_FLOAT(b, "Blue", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+CombineColorNode::CombineColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void CombineColorNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(svm_combine_color(color_type, make_float3(r, g, b)));
+ }
+}
+
+void CombineColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *red_in = input("Red");
+ ShaderInput *green_in = input("Green");
+ ShaderInput *blue_in = input("Blue");
+ ShaderOutput *color_out = output("Color");
+
+ int red_stack_offset = compiler.stack_assign(red_in);
+ int green_stack_offset = compiler.stack_assign(green_in);
+ int blue_stack_offset = compiler.stack_assign(blue_in);
+ int color_stack_offset = compiler.stack_assign(color_out);
+
+ compiler.add_node(
+ NODE_COMBINE_COLOR,
+ color_type,
+ compiler.encode_uchar4(red_stack_offset, green_stack_offset, blue_stack_offset),
+ color_stack_offset);
+}
+
+void CombineColorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "color_type");
+ compiler.add(this, "node_combine_color");
+}
+
/* Combine RGB */
NODE_DEFINE(CombineRGBNode)
@@ -5250,6 +5307,70 @@ void BrightContrastNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_brightness");
}
+/* Separate Color */
+
+NODE_DEFINE(SeparateColorNode)
+{
+ NodeType *type = NodeType::add("separate_color", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("rgb", NODE_COMBSEP_COLOR_RGB);
+ type_enum.insert("hsv", NODE_COMBSEP_COLOR_HSV);
+ type_enum.insert("hsl", NODE_COMBSEP_COLOR_HSL);
+ SOCKET_ENUM(color_type, "Type", type_enum, NODE_COMBSEP_COLOR_RGB);
+
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+
+ SOCKET_OUT_FLOAT(r, "Red");
+ SOCKET_OUT_FLOAT(g, "Green");
+ SOCKET_OUT_FLOAT(b, "Blue");
+
+ return type;
+}
+
+SeparateColorNode::SeparateColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void SeparateColorNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ float3 col = svm_separate_color(color_type, color);
+
+ for (int channel = 0; channel < 3; channel++) {
+ if (outputs[channel] == folder.output) {
+ folder.make_constant(col[channel]);
+ return;
+ }
+ }
+ }
+}
+
+void SeparateColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderOutput *red_out = output("Red");
+ ShaderOutput *green_out = output("Green");
+ ShaderOutput *blue_out = output("Blue");
+
+ int color_stack_offset = compiler.stack_assign(color_in);
+ int red_stack_offset = compiler.stack_assign(red_out);
+ int green_stack_offset = compiler.stack_assign(green_out);
+ int blue_stack_offset = compiler.stack_assign(blue_out);
+
+ compiler.add_node(
+ NODE_SEPARATE_COLOR,
+ color_type,
+ color_stack_offset,
+ compiler.encode_uchar4(red_stack_offset, green_stack_offset, blue_stack_offset));
+}
+
+void SeparateColorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "color_type");
+ compiler.add(this, "node_separate_color");
+}
+
/* Separate RGB */
NODE_DEFINE(SeparateRGBNode)
diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h
index 9aef5d3151f..ac40a397c1e 100644
--- a/intern/cycles/scene/shader_nodes.h
+++ b/intern/cycles/scene/shader_nodes.h
@@ -1101,6 +1101,17 @@ class MixNode : public ShaderNode {
NODE_SOCKET_API(float, fac)
};
+class CombineColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(CombineColorNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(NodeCombSepColorType, color_type)
+ NODE_SOCKET_API(float, r)
+ NODE_SOCKET_API(float, g)
+ NODE_SOCKET_API(float, b)
+};
+
class CombineRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineRGBNode)
@@ -1150,6 +1161,15 @@ class BrightContrastNode : public ShaderNode {
NODE_SOCKET_API(float, contrast)
};
+class SeparateColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(SeparateColorNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(NodeCombSepColorType, color_type)
+ NODE_SOCKET_API(float3, color)
+};
+
class SeparateRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateRGBNode)
diff --git a/intern/cycles/util/color.h b/intern/cycles/util/color.h
index cccccde3ba6..795c3754976 100644
--- a/intern/cycles/util/color.h
+++ b/intern/cycles/util/color.h
@@ -152,6 +152,56 @@ ccl_device float3 hsv_to_rgb(float3 hsv)
return rgb;
}
+ccl_device float3 rgb_to_hsl(float3 rgb)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z));
+ cmin = min(rgb.x, min(rgb.y, rgb.z));
+ l = min(1.0f, (cmax + cmin) / 2.0f);
+
+ if (cmax == cmin) {
+ h = s = 0.0f; /* achromatic */
+ }
+ else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5f ? cdelta / (2.0f - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb.x) {
+ h = (rgb.y - rgb.z) / cdelta + (rgb.y < rgb.z ? 6.0f : 0.0f);
+ }
+ else if (cmax == rgb.y) {
+ h = (rgb.z - rgb.x) / cdelta + 2.0f;
+ }
+ else {
+ h = (rgb.x - rgb.y) / cdelta + 4.0f;
+ }
+ }
+ h /= 6.0f;
+
+ return make_float3(h, s, l);
+}
+
+ccl_device float3 hsl_to_rgb(float3 hsl)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl.x;
+ s = hsl.y;
+ l = hsl.z;
+
+ nr = fabsf(h * 6.0f - 3.0f) - 1.0f;
+ ng = 2.0f - fabsf(h * 6.0f - 2.0f);
+ nb = 2.0f - fabsf(h * 6.0f - 4.0f);
+
+ nr = clamp(nr, 0.0f, 1.0f);
+ nb = clamp(nb, 0.0f, 1.0f);
+ ng = clamp(ng, 0.0f, 1.0f);
+
+ chroma = (1.0f - fabsf(2.0f * l - 1.0f)) * s;
+
+ return make_float3((nr - 0.5f) * chroma + l, (ng - 0.5f) * chroma + l, (nb - 0.5f) * chroma + l);
+}
+
ccl_device float3 xyY_to_xyz(float x, float y, float Y)
{
float X, Z;
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 83869188b65..ff02bc5781e 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -14,6 +14,7 @@
#endif
#include <commctrl.h>
+#include <dwmapi.h>
#include <psapi.h>
#include <shellapi.h>
#include <shellscalingapi.h>
@@ -1985,6 +1986,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
::SetFocus(hwnd);
}
break;
+ case WM_SETTINGCHANGE:
+ if (wcscmp(LPCWSTR(lParam), L"ImmersiveColorSet") == 0) {
+ window->ThemeRefresh();
+ }
+ break;
////////////////////////////////////////////////////////////////////////
// Window events, ignored
////////////////////////////////////////////////////////////////////////
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 2ce224b666b..f74a4b17a51 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -16,9 +16,7 @@
#include "GHOST_ContextWGL.h"
-#ifdef WIN32_COMPOSITING
-# include <Dwmapi.h>
-#endif
+#include <Dwmapi.h>
#include <assert.h>
#include <math.h>
@@ -172,6 +170,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
break;
}
+ ThemeRefresh();
+
::ShowWindow(m_hWnd, nCmdShow);
#ifdef WIN32_COMPOSITING
@@ -1016,6 +1016,25 @@ GHOST_TabletData GHOST_WindowWin32::getTabletData()
}
}
+void GHOST_WindowWin32::ThemeRefresh()
+{
+ DWORD lightMode;
+ DWORD pcbData = sizeof(lightMode);
+ if (RegGetValueW(HKEY_CURRENT_USER,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\\",
+ L"AppsUseLightTheme",
+ RRF_RT_REG_DWORD,
+ NULL,
+ &lightMode,
+ &pcbData) == ERROR_SUCCESS) {
+ BOOL DarkMode = !lightMode;
+
+ /* 20 == DWMWA_USE_IMMERSIVE_DARK_MODE in Windows 11 SDK. This value was undocumented for
+ * Windows 10 versions 2004 and later, supported for Windows 11 Build 22000 and later. */
+ DwmSetWindowAttribute(this->m_hWnd, 20, &DarkMode, sizeof(DarkMode));
+ }
+}
+
uint16_t GHOST_WindowWin32::getDPIHint()
{
if (m_user32) {
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index d5f47871aff..bc678adff3c 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -294,6 +294,9 @@ class GHOST_WindowWin32 : public GHOST_Window {
/** True if the window currently resizing. */
bool m_inLiveResize;
+ /** Called when OS colors change and when the window is created. */
+ void ThemeRefresh();
+
#ifdef WITH_INPUT_IME
GHOST_ImeWin32 *getImeInput()
{
diff --git a/release/datafiles/icons/ops.curves.sculpt_puff.dat b/release/datafiles/icons/ops.curves.sculpt_puff.dat
new file mode 100644
index 00000000000..db2bab46bfe
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_puff.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 44cf4b4bf74f22fff55941e39cebeacec68a5a8
+Subproject 2e715d54178e24ea463c7bc0cdeb27c682c39ec
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index 332ee39849e..eb1250cf5a5 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index b3f0c055769..4c6e2508859 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -1145,3 +1145,11 @@ class TextureNode(NodeInternal):
@classmethod
def poll(cls, ntree):
return ntree.bl_idname == 'TextureNodeTree'
+
+
+class GeometryNode(NodeInternal):
+ __slots__ = ()
+
+ @classmethod
+ def poll(cls, ntree):
+ return ntree.bl_idname == 'GeometryNodeTree'
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 78620c41d1e..99563c83bf9 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -1300,6 +1300,8 @@ def km_uv_editor(params):
{"properties": [("data_path", 'tool_settings.use_snap_uv')]}),
("wm.context_menu_enum", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("data_path", 'tool_settings.snap_uv_element')]}),
+ ("wm.context_toggle", {"type": 'ACCENT_GRAVE', "value": 'PRESS', "ctrl": True},
+ {"properties": [("data_path", 'space_data.show_gizmo')]}),
*_template_items_context_menu("IMAGE_MT_uvs_context_menu", params.context_menu_event),
])
@@ -1967,6 +1969,8 @@ def km_image(params):
),
("image.render_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
("image.clear_render_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None),
+ ("wm.context_toggle", {"type": 'ACCENT_GRAVE', "value": 'PRESS', "ctrl": True},
+ {"properties": [("data_path", 'space_data.show_gizmo')]}),
*_template_items_context_menu("IMAGE_MT_mask_context_menu", params.context_menu_event),
])
@@ -3977,6 +3981,8 @@ def km_grease_pencil_stroke_sculpt_mode(params):
("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
+ # Active material
+ op_menu("GPENCIL_MT_material_active", {"type": 'U', "value": 'PRESS'}),
# Merge Layer
("gpencil.layer_merge", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None),
# Keyframe menu
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 481753d5e79..189210d8540 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -41,17 +41,7 @@ class AnnotationDrawingToolsPanel:
row.prop_enum(tool_settings, "annotation_stroke_placement_view2d", 'IMAGE', text="Image")
-class GreasePencilSculptOptionsPanel:
- bl_label = "Sculpt Strokes"
-
- @classmethod
- def poll(cls, context):
- tool_settings = context.scene.tool_settings
- settings = tool_settings.gpencil_sculpt_paint
- brush = settings.brush
- tool = brush.gpencil_sculpt_tool
-
- return bool(tool in {'SMOOTH', 'RANDOMIZE'})
+class GreasePencilSculptAdvancedPanel:
def draw(self, context):
layout = self.layout
@@ -59,17 +49,21 @@ class GreasePencilSculptOptionsPanel:
layout.use_property_decorate = False
tool_settings = context.scene.tool_settings
- settings = tool_settings.gpencil_sculpt_paint
- brush = settings.brush
- gp_settings = brush.gpencil_settings
+ brush = context.tool_settings.gpencil_sculpt_paint.brush
tool = brush.gpencil_sculpt_tool
+ gp_settings = brush.gpencil_settings
- if tool in {'SMOOTH', 'RANDOMIZE'}:
- layout.prop(gp_settings, "use_edit_position", text="Affect Position")
- layout.prop(gp_settings, "use_edit_strength", text="Affect Strength")
- layout.prop(gp_settings, "use_edit_thickness", text="Affect Thickness")
+ col = layout.column(heading="Auto-Masking", align=True)
+ col.prop(gp_settings, "use_automasking_stroke", text="Stroke")
+ col.prop(gp_settings, "use_automasking_layer", text="Layer")
+ col.prop(gp_settings, "use_automasking_material", text="Material")
- layout.prop(gp_settings, "use_edit_uv", text="Affect UV")
+ if tool in {'SMOOTH', 'RANDOMIZE'}:
+ col = layout.column(heading="Affect", align=True)
+ col.prop(gp_settings, "use_edit_position", text="Position")
+ col.prop(gp_settings, "use_edit_strength", text="Strength")
+ col.prop(gp_settings, "use_edit_thickness", text="Thickness")
+ col.prop(gp_settings, "use_edit_uv", text="UV")
# GP Object Tool Settings
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 9a116aa1717..782fec91f91 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -769,6 +769,18 @@ def brush_settings(layout, context, brush, popover=False):
elif brush.color_type == 'GRADIENT':
layout.row().prop(brush, "gradient_fill_mode", expand=True)
+ elif mode == 'SCULPT_CURVES':
+ if brush.curves_sculpt_tool == 'ADD':
+ layout.prop(brush.curves_sculpt_settings, "add_amount")
+ layout.prop(brush.curves_sculpt_settings, "points_per_curve")
+ layout.prop(brush.curves_sculpt_settings, "curve_length")
+ layout.prop(brush.curves_sculpt_settings, "interpolate_length")
+ layout.prop(brush.curves_sculpt_settings, "interpolate_shape")
+ use_frontface = True
+ elif brush.curves_sculpt_tool == 'GROW_SHRINK':
+ layout.prop(brush.curves_sculpt_settings, "scale_uniform")
+ layout.prop(brush.curves_sculpt_settings, "minimum_length")
+
def brush_shared_settings(layout, context, brush, popover=False):
""" Draw simple brush settings that are shared between different paint modes. """
@@ -827,6 +839,7 @@ def brush_shared_settings(layout, context, brush, popover=False):
if mode == 'SCULPT_CURVES':
size = True
strength = True
+ direction = brush.curves_sculpt_tool == "GROW_SHRINK"
### Draw settings. ###
ups = context.scene.tool_settings.unified_paint_settings
@@ -925,16 +938,6 @@ def brush_settings_advanced(layout, context, brush, popover=False):
col.prop(brush, "use_original_plane", text="Plane")
layout.separator()
- elif mode == 'SCULPT_CURVES':
- if brush.curves_sculpt_tool == 'ADD':
- layout.prop(brush.curves_sculpt_settings, "add_amount")
- layout.prop(brush.curves_sculpt_settings, "curve_length")
- layout.prop(brush.curves_sculpt_settings, "interpolate_length")
- layout.prop(brush.curves_sculpt_settings, "interpolate_shape")
- elif brush.curves_sculpt_tool == 'GROW_SHRINK':
- layout.prop(brush.curves_sculpt_settings, "scale_uniform")
- layout.prop(brush.curves_sculpt_settings, "minimum_length")
-
# 3D and 2D Texture Paint.
elif mode in {'PAINT_TEXTURE', 'PAINT_2D'}:
capabilities = brush.image_paint_capabilities
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index 1dd50c979e2..d61055c9024 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -806,6 +806,13 @@ class IMAGE_HT_header(Header):
layout.separator_spacer()
+ # Gizmo toggle & popover.
+ row = layout.row(align=True)
+ row.prop(sima, "show_gizmo", icon='GIZMO', text="")
+ sub = row.row(align=True)
+ sub.active = sima.show_gizmo
+ sub.popover(panel="IMAGE_PT_gizmo_display", text="")
+
# Overlay toggle & popover
row = layout.row(align=True)
row.prop(overlay, "show_overlays", icon='OVERLAY', text="")
@@ -1453,6 +1460,26 @@ class IMAGE_PT_uv_cursor(Panel):
col.prop(sima, "cursor_location", text="Location")
+class IMAGE_PT_gizmo_display(Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'HEADER'
+ bl_label = "Gizmos"
+ bl_ui_units_x = 8
+
+ def draw(self, context):
+ layout = self.layout
+
+ view = context.space_data
+
+ col = layout.column()
+ col.label(text="Viewport Gizmos")
+ col.separator()
+
+ col.active = view.show_gizmo
+ colsub = col.column()
+ colsub.prop(view, "show_gizmo_navigate", text="Navigate")
+
+
class IMAGE_PT_overlay(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'
@@ -1680,6 +1707,7 @@ classes = (
IMAGE_PT_scope_sample,
IMAGE_PT_uv_cursor,
IMAGE_PT_annotation,
+ IMAGE_PT_gizmo_display,
IMAGE_PT_overlay,
IMAGE_PT_overlay_guides,
IMAGE_PT_overlay_uv_edit,
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index e0abb3a8d89..6654053bef4 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2274,6 +2274,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
self._draw_items(
context, (
({"property": "use_new_curves_type"}, "T68981"),
+ ({"property": "use_new_curves_tools"}, "T68981"),
({"property": "use_new_point_cloud_type"}, "T75717"),
({"property": "use_full_frame_compositor"}, "T88150"),
({"property": "enable_eevee_next"}, "T93220"),
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 3b966a28d33..b65079c0f36 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -109,8 +109,8 @@ class VIEW3D_HT_tool_header(Header):
if is_valid_context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
tool = brush.gpencil_sculpt_tool
- if tool in {'SMOOTH', 'RANDOMIZE'}:
- layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_options")
+ if tool != 'CLONE':
+ layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover")
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'WEIGHT_GPENCIL':
if is_valid_context:
@@ -151,6 +151,11 @@ class VIEW3D_HT_tool_header(Header):
row.popover(panel="VIEW3D_PT_sculpt_symmetry_for_topbar", text="")
elif mode_string == 'PAINT_VERTEX':
row.popover(panel="VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar", text="")
+ elif mode_string == 'SCULPT_CURVES':
+ _row, sub = row_for_mirror()
+ sub.prop(context.object.data, "use_mirror_x", text="X", toggle=True)
+ sub.prop(context.object.data, "use_mirror_y", text="Y", toggle=True)
+ sub.prop(context.object.data, "use_mirror_z", text="Z", toggle=True)
# Expand panels from the side-bar as popovers.
popover_kw = {"space_type": 'VIEW_3D', "region_type": 'UI', "category": "Tool"}
@@ -511,9 +516,10 @@ class _draw_tool_settings_context_mode:
layout.prop(brush, "curve_preset")
if brush.curves_sculpt_tool == 'ADD':
- layout.prop(brush, "use_frontface")
+ layout.prop(brush, "use_frontface", text="Front Faces Only")
layout.prop(brush, "falloff_shape", expand=True)
layout.prop(brush.curves_sculpt_settings, "add_amount")
+ layout.prop(brush.curves_sculpt_settings, "points_per_curve")
layout.prop(brush.curves_sculpt_settings, "curve_length")
layout.prop(brush.curves_sculpt_settings, "interpolate_length")
layout.prop(brush.curves_sculpt_settings, "interpolate_shape")
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 570d7c12e30..698f0dadc33 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -3,7 +3,7 @@
# <pep8 compliant>
from bpy.types import Menu, Panel, UIList
from bl_ui.properties_grease_pencil_common import (
- GreasePencilSculptOptionsPanel,
+ GreasePencilSculptAdvancedPanel,
GreasePencilDisplayPanel,
GreasePencilBrushFalloff,
)
@@ -1049,6 +1049,36 @@ class VIEW3D_PT_sculpt_symmetry_for_topbar(Panel):
draw = VIEW3D_PT_sculpt_symmetry.draw
+class VIEW3D_PT_curves_sculpt_symmetry(Panel, View3DPaintPanel):
+ bl_context = ".curves_sculpt" # dot on purpose (access from topbar)
+ bl_label = "Symmetry"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.object and context.object.type == 'CURVES'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+
+ curves = context.object.data
+
+ row = layout.row(align=True, heading="Mirror")
+ row.prop(curves, "use_mirror_x", text="X", toggle=True)
+ row.prop(curves, "use_mirror_y", text="Y", toggle=True)
+ row.prop(curves, "use_mirror_z", text="Z", toggle=True)
+
+
+class VIEW3D_PT_curves_sculpt_symmetry_for_topbar(Panel):
+ bl_space_type = 'TOPBAR'
+ bl_region_type = 'HEADER'
+ bl_label = "Symmetry"
+
+ draw = VIEW3D_PT_curves_sculpt_symmetry.draw
+
+
# ********** default tools for weight-paint ****************
@@ -1907,6 +1937,41 @@ class VIEW3D_PT_tools_grease_pencil_brush_sculpt_falloff(GreasePencilBrushFallof
return (settings and settings.brush and settings.brush.curve)
+class VIEW3D_PT_tools_grease_pencil_sculpt_brush_advanced(GreasePencilSculptAdvancedPanel, View3DPanel, Panel):
+ bl_context = ".greasepencil_sculpt"
+ bl_label = "Advanced"
+ bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_sculpt_settings'
+ bl_category = "Tool"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ brush = context.tool_settings.gpencil_sculpt_paint.brush
+ if brush is None:
+ return False
+
+ tool = brush.gpencil_sculpt_tool
+ return tool != 'CLONE'
+
+
+class VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover(GreasePencilSculptAdvancedPanel, View3DPanel, Panel):
+ bl_context = ".greasepencil_sculpt"
+ bl_label = "Brush"
+ bl_category = "Tool"
+
+ @classmethod
+ def poll(cls, context):
+ if context.region.type != 'TOOL_HEADER':
+ return False
+
+ brush = context.tool_settings.gpencil_sculpt_paint.brush
+ if brush is None:
+ return False
+
+ tool = brush.gpencil_sculpt_tool
+ return tool != 'CLONE'
+
+
# Grease Pencil weight painting tools
class GreasePencilWeightPanel:
bl_context = ".greasepencil_weight"
@@ -2240,13 +2305,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_mix_palette(View3DPanel, Panel):
col.template_palette(settings, "palette", color=True)
-class VIEW3D_PT_tools_grease_pencil_sculpt_options(GreasePencilSculptOptionsPanel, Panel, View3DPanel):
- bl_context = ".greasepencil_sculpt"
- bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_sculpt_settings'
- bl_category = "Tool"
- bl_label = "Sculpt Strokes"
-
-
# Grease Pencil Brush Appearance (one for each mode)
class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilDisplayPanel, Panel, View3DPanel):
bl_context = ".greasepencil_paint"
@@ -2323,6 +2381,9 @@ classes = (
VIEW3D_PT_sculpt_options,
VIEW3D_PT_sculpt_options_gravity,
+ VIEW3D_PT_curves_sculpt_symmetry,
+ VIEW3D_PT_curves_sculpt_symmetry_for_topbar,
+
VIEW3D_PT_tools_weightpaint_symmetry,
VIEW3D_PT_tools_weightpaint_symmetry_for_topbar,
VIEW3D_PT_tools_weightpaint_options,
@@ -2357,7 +2418,8 @@ classes = (
VIEW3D_PT_tools_grease_pencil_paint_appearance,
VIEW3D_PT_tools_grease_pencil_sculpt_select,
VIEW3D_PT_tools_grease_pencil_sculpt_settings,
- VIEW3D_PT_tools_grease_pencil_sculpt_options,
+ VIEW3D_PT_tools_grease_pencil_sculpt_brush_advanced,
+ VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover,
VIEW3D_PT_tools_grease_pencil_sculpt_appearance,
VIEW3D_PT_tools_grease_pencil_weight_paint_select,
VIEW3D_PT_tools_grease_pencil_weight_paint_settings,
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 4f94184f006..817c53cca62 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -419,12 +419,10 @@ shader_node_categories = [
NodeItem("ShaderNodeRGBToBW"),
NodeItem("ShaderNodeShaderToRGB", poll=object_eevee_shader_nodes_poll),
NodeItem("ShaderNodeVectorMath"),
- NodeItem("ShaderNodeSeparateRGB"),
- NodeItem("ShaderNodeCombineRGB"),
+ NodeItem("ShaderNodeSeparateColor"),
+ NodeItem("ShaderNodeCombineColor"),
NodeItem("ShaderNodeSeparateXYZ"),
NodeItem("ShaderNodeCombineXYZ"),
- NodeItem("ShaderNodeSeparateHSV"),
- NodeItem("ShaderNodeCombineHSV"),
NodeItem("ShaderNodeWavelength"),
NodeItem("ShaderNodeBlackbody"),
]),
@@ -483,14 +481,8 @@ compositor_node_categories = [
NodeItem("CompositorNodePremulKey"),
NodeItem("CompositorNodeIDMask"),
NodeItem("CompositorNodeRGBToBW"),
- NodeItem("CompositorNodeSepRGBA"),
- NodeItem("CompositorNodeCombRGBA"),
- NodeItem("CompositorNodeSepHSVA"),
- NodeItem("CompositorNodeCombHSVA"),
- NodeItem("CompositorNodeSepYUVA"),
- NodeItem("CompositorNodeCombYUVA"),
- NodeItem("CompositorNodeSepYCCA"),
- NodeItem("CompositorNodeCombYCCA"),
+ NodeItem("CompositorNodeSeparateColor"),
+ NodeItem("CompositorNodeCombineColor"),
NodeItem("CompositorNodeSeparateXYZ"),
NodeItem("CompositorNodeCombineXYZ"),
NodeItem("CompositorNodeSwitchView"),
@@ -576,8 +568,8 @@ texture_node_categories = [
NodeItem("TextureNodeCurveRGB"),
NodeItem("TextureNodeInvert"),
NodeItem("TextureNodeHueSaturation"),
- NodeItem("TextureNodeCompose"),
- NodeItem("TextureNodeDecompose"),
+ NodeItem("TextureNodeCombineColor"),
+ NodeItem("TextureNodeSeparateColor"),
]),
TextureNodeCategory("TEX_PATTERN", "Pattern", items=[
NodeItem("TextureNodeChecker"),
@@ -629,8 +621,8 @@ geometry_node_categories = [
NodeItem("ShaderNodeMixRGB"),
NodeItem("ShaderNodeRGBCurve"),
NodeItem("ShaderNodeValToRGB"),
- NodeItem("ShaderNodeSeparateRGB"),
- NodeItem("ShaderNodeCombineRGB"),
+ NodeItem("FunctionNodeSeparateColor"),
+ NodeItem("FunctionNodeCombineColor"),
]),
GeometryNodeCategory("GEO_CURVE", "Curve", items=curve_node_items),
GeometryNodeCategory("GEO_PRIMITIVES_CURVE", "Curve Primitives", items=[
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 15fdc73adeb..ab13a2e85d0 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -17,15 +17,15 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 302
+#define BLENDER_VERSION 303
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 14
+#define BLENDER_FILE_SUBVERSION 0
/* 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_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 1e96c0e4c41..bf2d50f63be 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -48,6 +48,13 @@ struct BasisCache {
* In other words, the index of the first control point that influences this evaluated point.
*/
Vector<int> start_indices;
+
+ /**
+ * The result of #check_valid_size_and_order, to avoid retrieving its inputs later on.
+ * If this is true, the data above will be invalid, and original data should be copied
+ * to the evaluated result.
+ */
+ bool invalid = false;
};
} // namespace curves::nurbs
@@ -174,11 +181,18 @@ class CurvesGeometry : public ::CurvesGeometry {
/** Update the cached count of curves of each type, necessary after #curve_types_for_write. */
void update_curve_types();
- bool has_curve_with_type(const CurveType type) const;
+ bool has_curve_with_type(CurveType type) const;
/** Return true if all of the curves have the provided type. */
bool is_single_type(CurveType type) const;
/** Return the number of curves with each type. */
const std::array<int, CURVE_TYPES_NUM> &curve_type_counts() const;
+ /**
+ * All of the curve indices for curves with a specific type.
+ */
+ IndexMask indices_for_curve_type(CurveType type, Vector<int64_t> &r_indices) const;
+ IndexMask indices_for_curve_type(CurveType type,
+ IndexMask selection,
+ Vector<int64_t> &r_indices) const;
Span<float3> positions() const;
MutableSpan<float3> positions_for_write();
@@ -276,11 +290,6 @@ class CurvesGeometry : public ::CurvesGeometry {
bool bounds_min_max(float3 &min, float3 &max) const;
private:
- /**
- * All of the curve indices for curves with a specific type.
- */
- IndexMask indices_for_curve_type(CurveType type, Vector<int64_t> &r_indices) const;
-
/* --------------------------------------------------------------------
* Evaluation.
*/
@@ -760,7 +769,7 @@ inline IndexRange CurvesGeometry::lengths_range_for_curve(const int curve_index,
BLI_assert(cyclic == this->cyclic()[curve_index]);
const IndexRange points = this->evaluated_points_for_curve(curve_index);
const int start = points.start() + curve_index;
- return {start, points.is_empty() ? 0 : curves::curve_segment_size(points.size(), cyclic)};
+ return {start, curves::curve_segment_size(points.size(), cyclic)};
}
inline Span<float> CurvesGeometry::evaluated_lengths_for_curve(const int curve_index,
@@ -775,8 +784,7 @@ inline float CurvesGeometry::evaluated_length_total_for_curve(const int curve_in
const bool cyclic) const
{
const Span<float> lengths = this->evaluated_lengths_for_curve(curve_index, cyclic);
- /* Check for curves that have no evaluated segments. */
- return lengths.is_empty() ? 0.0f : lengths.last();
+ return lengths.last();
}
/** \} */
diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh
index 36b382feb5f..9c86ab262ef 100644
--- a/source/blender/blenkernel/BKE_geometry_fields.hh
+++ b/source/blender/blenkernel/BKE_geometry_fields.hh
@@ -162,4 +162,14 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
+class CurveLengthFieldInput final : public GeometryFieldInput {
+ public:
+ CurveLengthFieldInput();
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ AttributeDomain domain,
+ IndexMask mask) const final;
+ uint64_t hash() const override;
+ bool is_equal_to(const fn::FieldNode &other) const override;
+};
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_lib_principle_properties.h b/source/blender/blenkernel/BKE_lib_principle_properties.h
index 10d0d33a0c4..42177204efb 100644
--- a/source/blender/blenkernel/BKE_lib_principle_properties.h
+++ b/source/blender/blenkernel/BKE_lib_principle_properties.h
@@ -40,7 +40,7 @@ struct ReportList;
struct IDPrincipleProperties *BKE_lib_principleprop_init(struct ID *id);
#if 0
/**
- * Shallow or deep copy of a whole princple properties from \a src_id to \a dst_id.
+ * Shallow or deep copy of a whole principle properties from \a src_id to \a dst_id.
*/
void BKE_lib_principleprop_copy(struct ID *dst_id, const struct ID *src_id, bool do_full_copy);
#endif
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 881e86ccc54..a38bfb497a2 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -113,7 +113,7 @@ typedef enum ModifierApplyFlag {
/** Render time. */
MOD_APPLY_RENDER = 1 << 0,
/** Result of evaluation will be cached, so modifier might
- * want to cache data for quick updates (used by subsurf) */
+ * want to cache data for quick updates (used by subdivision-surface) */
MOD_APPLY_USECACHE = 1 << 1,
/** Modifier evaluated for undeformed texture coordinates */
MOD_APPLY_ORCO = 1 << 2,
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index c9228db9ecc..1ff10d06b00 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1090,8 +1090,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_SQUEEZE 117
//#define SH_NODE_MATERIAL_EXT 118
#define SH_NODE_INVERT 119
-#define SH_NODE_SEPRGB 120
-#define SH_NODE_COMBRGB 121
+#define SH_NODE_SEPRGB_LEGACY 120
+#define SH_NODE_COMBRGB_LEGACY 121
#define SH_NODE_HUE_SAT 122
#define SH_NODE_OUTPUT_MATERIAL 124
@@ -1147,8 +1147,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_WAVELENGTH 180
#define SH_NODE_BLACKBODY 181
#define SH_NODE_VECT_TRANSFORM 182
-#define SH_NODE_SEPHSV 183
-#define SH_NODE_COMBHSV 184
+#define SH_NODE_SEPHSV_LEGACY 183
+#define SH_NODE_COMBHSV_LEGACY 184
#define SH_NODE_BSDF_HAIR 185
// #define SH_NODE_LAMP 186
#define SH_NODE_UVMAP 187
@@ -1175,6 +1175,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_VECTOR_ROTATE 708
#define SH_NODE_CURVE_FLOAT 709
#define SH_NODE_POINT_INFO 710
+#define SH_NODE_COMBINE_COLOR 711
+#define SH_NODE_SEPARATE_COLOR 712
/** \} */
@@ -1202,8 +1204,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_MAP_VALUE 213
#define CMP_NODE_TIME 214
#define CMP_NODE_VECBLUR 215
-#define CMP_NODE_SEPRGBA 216
-#define CMP_NODE_SEPHSVA 217
+#define CMP_NODE_SEPRGBA_LEGACY 216
+#define CMP_NODE_SEPHSVA_LEGACY 217
#define CMP_NODE_SETALPHA 218
#define CMP_NODE_HUE_SAT 219
#define CMP_NODE_IMAGE 220
@@ -1213,14 +1215,14 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_TEXTURE 224
#define CMP_NODE_TRANSLATE 225
#define CMP_NODE_ZCOMBINE 226
-#define CMP_NODE_COMBRGBA 227
+#define CMP_NODE_COMBRGBA_LEGACY 227
#define CMP_NODE_DILATEERODE 228
#define CMP_NODE_ROTATE 229
#define CMP_NODE_SCALE 230
-#define CMP_NODE_SEPYCCA 231
-#define CMP_NODE_COMBYCCA 232
-#define CMP_NODE_SEPYUVA 233
-#define CMP_NODE_COMBYUVA 234
+#define CMP_NODE_SEPYCCA_LEGACY 231
+#define CMP_NODE_COMBYCCA_LEGACY 232
+#define CMP_NODE_SEPYUVA_LEGACY 233
+#define CMP_NODE_COMBYUVA_LEGACY 234
#define CMP_NODE_DIFF_MATTE 235
#define CMP_NODE_COLOR_SPILL 236
#define CMP_NODE_CHROMA_MATTE 237
@@ -1232,7 +1234,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_ID_MASK 243
#define CMP_NODE_DEFOCUS 244
#define CMP_NODE_DISPLACE 245
-#define CMP_NODE_COMBHSVA 246
+#define CMP_NODE_COMBHSVA_LEGACY 246
#define CMP_NODE_MATH 247
#define CMP_NODE_LUMA_MATTE 248
#define CMP_NODE_BRIGHTCONTRAST 249
@@ -1289,6 +1291,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_SCENE_TIME 329
#define CMP_NODE_SEPARATE_XYZ 330
#define CMP_NODE_COMBINE_XYZ 331
+#define CMP_NODE_COMBINE_COLOR 332
+#define CMP_NODE_SEPARATE_COLOR 333
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -1354,11 +1358,13 @@ struct TexResult;
#define TEX_NODE_TRANSLATE 416
#define TEX_NODE_COORD 417
#define TEX_NODE_DISTANCE 418
-#define TEX_NODE_COMPOSE 419
-#define TEX_NODE_DECOMPOSE 420
+#define TEX_NODE_COMPOSE_LEGACY 419
+#define TEX_NODE_DECOMPOSE_LEGACY 420
#define TEX_NODE_VALTONOR 421
#define TEX_NODE_SCALE 422
#define TEX_NODE_AT 423
+#define TEX_NODE_COMBINE_COLOR 424
+#define TEX_NODE_SEPARATE_COLOR 425
/* 501-599 reserved. Use like this: TEX_NODE_PROC + TEX_CLOUDS, etc */
#define TEX_NODE_PROC 500
@@ -1511,6 +1517,8 @@ struct TexResult;
#define FN_NODE_REPLACE_STRING 1218
#define FN_NODE_INPUT_BOOL 1219
#define FN_NODE_INPUT_INT 1220
+#define FN_NODE_SEPARATE_COLOR 1221
+#define FN_NODE_COMBINE_COLOR 1222
/** \} */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 0e976f04dd1..03cbcf575c3 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -733,7 +733,7 @@ enum {
/* paint_vertex.cc */
/**
- * Fills the object's active color atribute layer with the fill color.
+ * Fills the object's active color attribute layer with the fill color.
*
* \param[in] ob: The object.
* \param[in] fill_color: The fill color.
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index a57d4d0a2bf..c9e88362b80 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -242,8 +242,8 @@ set(SRC
intern/particle_child.c
intern/particle_distribute.c
intern/particle_system.c
- intern/pbvh.cc
intern/pbvh.c
+ intern/pbvh.cc
intern/pbvh_bmesh.c
intern/pbvh_pixels.cc
intern/pointcache.c
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index 555c4690308..e2f22ef00d3 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -1564,7 +1564,7 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
}
if (GS(old_id->name) == ID_KE) {
- /* Shape Keys are handled as part of their owning obdata (see below). This implies thar
+ /* Shape Keys are handled as part of their owning obdata (see below). This implies that
* there is no way to know when the old pointer gets invalid, so just clear it immediately.
*/
item->userdata = NULL;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 0593db34e20..e8c95869910 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1559,6 +1559,7 @@ void BKE_brush_init_curves_sculpt_settings(Brush *brush)
}
BrushCurvesSculptSettings *settings = brush->curves_sculpt_settings;
settings->add_amount = 1;
+ settings->points_per_curve = 8;
settings->minimum_length = 0.01f;
settings->curve_length = 0.3f;
}
diff --git a/source/blender/blenkernel/intern/curve_nurbs.cc b/source/blender/blenkernel/intern/curve_nurbs.cc
index 0114c0b45f4..45440358221 100644
--- a/source/blender/blenkernel/intern/curve_nurbs.cc
+++ b/source/blender/blenkernel/intern/curve_nurbs.cc
@@ -36,7 +36,7 @@ int calculate_evaluated_size(const int points_num,
const KnotsMode knots_mode)
{
if (!check_valid_size_and_order(points_num, order, cyclic, knots_mode)) {
- return 0;
+ return points_num;
}
return resolution * curve_segment_size(points_num, cyclic);
}
@@ -232,8 +232,12 @@ void interpolate_to_evaluated(const BasisCache &basis_cache,
const GSpan src,
GMutableSpan dst)
{
- BLI_assert(dst.size() == basis_cache.start_indices.size());
+ if (basis_cache.invalid) {
+ dst.copy_from(src);
+ return;
+ }
+ BLI_assert(dst.size() == basis_cache.start_indices.size());
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
diff --git a/source/blender/blenkernel/intern/curve_poly.cc b/source/blender/blenkernel/intern/curve_poly.cc
index 2db7cd71ad3..1b337379604 100644
--- a/source/blender/blenkernel/intern/curve_poly.cc
+++ b/source/blender/blenkernel/intern/curve_poly.cc
@@ -110,7 +110,7 @@ void calculate_normals_minimum(const Span<float3> tangents,
normals.first() = math::normalize(float3(first_tangent.y, -first_tangent.x, 0.0f));
}
- /* Forward normal with minimum twist along the entire spline. */
+ /* Forward normal with minimum twist along the entire curve. */
for (const int i : IndexRange(1, normals.size() - 1)) {
normals[i] = calculate_next_normal(normals[i - 1], tangents[i - 1], tangents[i]);
}
@@ -120,7 +120,7 @@ void calculate_normals_minimum(const Span<float3> tangents,
}
/* Compute how much the first normal deviates from the normal that has been forwarded along the
- * entire cyclic spline. */
+ * entire cyclic curve. */
const float3 uncorrected_last_normal = calculate_next_normal(
normals.last(), tangents.last(), tangents.first());
float correction_angle = angle_signed_on_axis_v3v3_v3(
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 88e0bae0c13..ef921797698 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -668,12 +668,12 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
Vector<std::byte> eval_buffer;
- Curves main_id = {nullptr};
+ Curves main_id = {{nullptr}};
main_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(main);
CurveComponent main_component;
main_component.replace(&main_id, GeometryOwnershipType::Editable);
- Curves profile_id = {nullptr};
+ Curves profile_id = {{nullptr}};
profile_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(profile);
CurveComponent profile_component;
profile_component.replace(&profile_id, GeometryOwnershipType::Editable);
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index 7a09b87490b..e7337d5c012 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -250,6 +250,10 @@ void CurvesGeometry::fill_curve_types(const CurveType type)
void CurvesGeometry::fill_curve_types(const IndexMask selection, const CurveType type)
{
+ if (selection.size() == this->curves_num()) {
+ this->fill_curve_types(type);
+ return;
+ }
/* A potential performance optimization is only counting the changed indices. */
this->curve_types_for_write().fill_indices(selection, type);
this->update_curve_types();
@@ -527,19 +531,19 @@ Span<int> CurvesGeometry::evaluated_offsets() const
IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
Vector<int64_t> &r_indices) const
{
+ return this->indices_for_curve_type(type, this->curves_range(), r_indices);
+}
- VArray<int8_t> types = this->curve_types();
- if (types.is_single()) {
- if (types.get_internal_single() == type) {
- return IndexMask(types.size());
- }
- return {};
+IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
+ const IndexMask selection,
+ Vector<int64_t> &r_indices) const
+{
+ if (this->curve_type_counts()[type] == this->curves_num()) {
+ return selection;
}
- Span<int8_t> types_span = types.get_internal_span();
+ Span<int8_t> types_span = this->curve_types().get_internal_span();
return index_mask_ops::find_indices_based_on_predicate(
- IndexMask(types.size()), 1024, r_indices, [&](const int index) {
- return types_span[index] == type;
- });
+ selection, 1024, r_indices, [&](const int index) { return types_span[index] == type; });
}
void CurvesGeometry::ensure_nurbs_basis_cache() const
@@ -577,6 +581,11 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
const bool is_cyclic = cyclic[curve_index];
const KnotsMode mode = KnotsMode(knots_modes[curve_index]);
+ if (!curves::nurbs::check_valid_size_and_order(points.size(), order, is_cyclic, mode)) {
+ basis_caches[curve_index].invalid = true;
+ continue;
+ }
+
const int knots_size = curves::nurbs::knots_size(points.size(), order, is_cyclic);
Array<float> knots(knots_size);
curves::nurbs::calculate_knots(points.size(), mode, order, is_cyclic, knots);
@@ -696,9 +705,6 @@ Span<float3> CurvesGeometry::evaluated_tangents() const
threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
for (const int curve_index : curves_range) {
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
- if (UNLIKELY(evaluated_points.is_empty())) {
- continue;
- }
curves::poly::calculate_tangents(evaluated_positions.slice(evaluated_points),
cyclic[curve_index],
tangents.slice(evaluated_points));
@@ -773,9 +779,6 @@ Span<float3> CurvesGeometry::evaluated_normals() const
for (const int curve_index : curves_range) {
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
- if (UNLIKELY(evaluated_points.is_empty())) {
- continue;
- }
switch (normal_mode[curve_index]) {
case NORMAL_MODE_Z_UP:
curves::poly::calculate_normals_z_up(evaluated_tangents.slice(evaluated_points),
@@ -916,9 +919,6 @@ void CurvesGeometry::ensure_evaluated_lengths() const
for (const int curve_index : curves_range) {
const bool cyclic = curves_cyclic[curve_index];
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
- if (UNLIKELY(evaluated_points.is_empty())) {
- continue;
- }
const IndexRange lengths_range = this->lengths_range_for_curve(curve_index, cyclic);
length_parameterize::accumulate_lengths(evaluated_positions.slice(evaluated_points),
cyclic,
@@ -1196,6 +1196,8 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
}
});
+ new_curves.update_curve_types();
+
return new_curves;
}
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index bc9bba3ee2f..7c4a7db6462 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -237,6 +237,69 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const Attri
return nullptr;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve Length Field Input
+ * \{ */
+
+static VArray<float> construct_curve_length_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
+{
+ if (!component.has_curves()) {
+ return {};
+ }
+ const Curves &curves_id = *component.get_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+
+ curves.ensure_evaluated_lengths();
+
+ VArray<bool> cyclic = curves.cyclic();
+ VArray<float> lengths = VArray<float>::ForFunc(
+ curves.curves_num(), [&curves, cyclic = std::move(cyclic)](int64_t index) {
+ return curves.evaluated_length_total_for_curve(index, cyclic[index]);
+ });
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ return lengths;
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ return component.attribute_try_adapt_domain<float>(
+ std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ }
+
+ return {};
+}
+
+CurveLengthFieldInput::CurveLengthFieldInput()
+ : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
+{
+ category_ = Category::Generated;
+}
+
+GVArray CurveLengthFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const
+{
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_curve_length_gvarray(curve_component, domain);
+ }
+ return {};
+}
+
+uint64_t CurveLengthFieldInput::hash() const
+{
+ /* Some random constant hash. */
+ return 3549623580;
+}
+
+bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr;
+}
+
} // namespace blender::bke
/** \} */
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 200eefb73ec..ffa39f79e7c 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4502,6 +4502,8 @@ static void registerCompositNodes()
register_node_type_cmp_premulkey();
register_node_type_cmp_separate_xyz();
register_node_type_cmp_combine_xyz();
+ register_node_type_cmp_separate_color();
+ register_node_type_cmp_combine_color();
register_node_type_cmp_diff_matte();
register_node_type_cmp_distance_matte();
@@ -4574,6 +4576,8 @@ static void registerShaderNodes()
register_node_type_sh_vect_transform();
register_node_type_sh_squeeze();
register_node_type_sh_invert();
+ register_node_type_sh_sepcolor();
+ register_node_type_sh_combcolor();
register_node_type_sh_seprgb();
register_node_type_sh_combrgb();
register_node_type_sh_sephsv();
@@ -4660,6 +4664,8 @@ static void registerTextureNodes()
register_node_type_tex_distance();
register_node_type_tex_compose();
register_node_type_tex_decompose();
+ register_node_type_tex_combine_color();
+ register_node_type_tex_separate_color();
register_node_type_tex_output();
register_node_type_tex_viewer();
@@ -4821,6 +4827,7 @@ static void registerFunctionNodes()
{
register_node_type_fn_align_euler_to_vector();
register_node_type_fn_boolean_math();
+ register_node_type_fn_combine_color();
register_node_type_fn_compare();
register_node_type_fn_float_to_int();
register_node_type_fn_input_bool();
@@ -4832,6 +4839,7 @@ static void registerFunctionNodes()
register_node_type_fn_random_value();
register_node_type_fn_replace_string();
register_node_type_fn_rotate_euler();
+ register_node_type_fn_separate_color();
register_node_type_fn_slice_string();
register_node_type_fn_string_length();
register_node_type_fn_value_to_string();
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 2a25d73ed87..7f5146f14e0 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -2114,7 +2114,7 @@ static const char *get_obdata_defname(int type)
case OB_SPEAKER:
return DATA_("Speaker");
case OB_CURVES:
- return DATA_("HairCurves");
+ return DATA_("Curves");
case OB_POINTCLOUD:
return DATA_("PointCloud");
case OB_VOLUME:
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
index 1c5078df1f3..12a5f00a68b 100644
--- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -295,16 +295,16 @@ static void init_functions(OpenSubdiv_Converter *converter)
static void initialize_manifold_index_array(const BLI_bitmap *used_map,
const int num_elements,
- int **indices_r,
- int **indices_reverse_r,
- int *num_manifold_elements_r)
+ int **r_indices,
+ int **r_indices_reverse,
+ int *r_num_manifold_elements)
{
int *indices = NULL;
- if (indices_r != NULL) {
+ if (r_indices != NULL) {
indices = MEM_malloc_arrayN(num_elements, sizeof(int), "manifold indices");
}
int *indices_reverse = NULL;
- if (indices_reverse_r != NULL) {
+ if (r_indices_reverse != NULL) {
indices_reverse = MEM_malloc_arrayN(num_elements, sizeof(int), "manifold indices reverse");
}
int offset = 0;
@@ -324,13 +324,13 @@ static void initialize_manifold_index_array(const BLI_bitmap *used_map,
offset++;
}
}
- if (indices_r != NULL) {
- *indices_r = indices;
+ if (r_indices != NULL) {
+ *r_indices = indices;
}
- if (indices_reverse_r != NULL) {
- *indices_reverse_r = indices_reverse;
+ if (r_indices_reverse != NULL) {
+ *r_indices_reverse = indices_reverse;
}
- *num_manifold_elements_r = num_elements - offset;
+ *r_num_manifold_elements = num_elements - offset;
}
static void initialize_manifold_indices(ConverterStorage *storage)
diff --git a/source/blender/blenkernel/intern/tracking_plane_tracker.c b/source/blender/blenkernel/intern/tracking_plane_tracker.c
index 5e60f6f59a9..c4379ea61bc 100644
--- a/source/blender/blenkernel/intern/tracking_plane_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_plane_tracker.c
@@ -21,12 +21,12 @@
typedef double Vec2[2];
static int point_markers_correspondences_on_both_image(
- MovieTrackingPlaneTrack *plane_track, int frame1, int frame2, Vec2 **x1_r, Vec2 **x2_r)
+ MovieTrackingPlaneTrack *plane_track, int frame1, int frame2, Vec2 **r_x1, Vec2 **r_x2)
{
Vec2 *x1, *x2;
- *x1_r = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1");
- *x2_r = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2");
+ *r_x1 = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1");
+ *r_x2 = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2");
int correspondence_index = 0;
for (int i = 0; i < plane_track->point_tracksnr; i++) {
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e0f28522d6c..4e76ae3e855 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -79,8 +79,8 @@ set(SRC
intern/kdtree_3d.c
intern/kdtree_4d.c
intern/lasso_2d.c
- intern/listbase.c
intern/length_parameterize.cc
+ intern/listbase.c
intern/math_base.c
intern/math_base_inline.c
intern/math_base_safe_inline.c
@@ -274,8 +274,8 @@ set(SRC
BLI_multi_value_map.hh
BLI_noise.h
BLI_noise.hh
- BLI_path_util.h
BLI_parameter_pack_utils.hh
+ BLI_path_util.h
BLI_polyfill_2d.h
BLI_polyfill_2d_beautify.h
BLI_probing_strategies.hh
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index aeeaf47d813..07e9eaf0f42 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -238,7 +238,7 @@ void rgb_to_hsl(float r, float g, float b, float *r_h, float *r_s, float *r_l)
{
const float cmax = max_fff(r, g, b);
const float cmin = min_fff(r, g, b);
- float h, s, l = min_ff(1.0, (cmax + cmin) / 2.0f);
+ float h, s, l = min_ff(1.0f, (cmax + cmin) / 2.0f);
if (cmax == cmin) {
h = s = 0.0f; /* achromatic */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 27890a908ab..6ba97caa0ae 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2068,7 +2068,7 @@ static void direct_link_id_embedded_id(BlendDataReader *reader,
static int direct_link_id_restore_recalc_exceptions(const ID *id_current)
{
/* Exception for armature objects, where the pose has direct points to the
- * armature databolock. */
+ * armature data-block. */
if (GS(id_current->name) == ID_OB && ((Object *)id_current)->pose) {
return ID_RECALC_GEOMETRY;
}
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index e6a214452fe..7fd72fec3d0 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -2735,6 +2735,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
FOREACH_NODETREE_END;
+
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(
+ ntree, GEO_NODE_SUBDIVISION_SURFACE, "Crease", "Edge Crease");
+ }
+ }
}
if (!MAIN_VERSION_ATLEAST(bmain, 302, 13)) {
@@ -2772,5 +2779,260 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Replace legacy combine/separate color nodes */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ /* In geometry nodes, replace shader combine/separate color nodes with function nodes */
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = FN_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = FN_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with
+ * combine/separate color */
+ if (ntree->type == NTREE_COMPOSIT) {
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case CMP_NODE_COMBRGBA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBHSVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYCCA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYUVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPRGBA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPHSVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYCCA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYUVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In texture nodes, replace combine/separate RGBA with combine/separate color */
+ if (ntree->type == NTREE_TEXTURE) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case TEX_NODE_COMPOSE_LEGACY: {
+ node->type = TEX_NODE_COMBINE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeCombineColor");
+ break;
+ }
+ case TEX_NODE_DECOMPOSE_LEGACY: {
+ node->type = TEX_NODE_SEPARATE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeSeparateColor");
+ break;
+ }
+ }
+ }
+ }
+
+ /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */
+ if (ntree->type == NTREE_SHADER) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_COMBHSV_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPHSV_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ /* Initialize brush curves sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
+ continue;
+ }
+ if (brush->curves_sculpt_settings->points_per_curve == 0) {
+ brush->curves_sculpt_settings->points_per_curve = 8;
+ }
+ }
}
}
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 0246850123a..9d5737a5b71 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -265,8 +265,20 @@ typedef struct BMFace {
* (the length of #BMFace.l_first circular linked list).
*/
int len;
- float no[3]; /* face normal */
- short mat_nr; /* material index */
+ /**
+ * Face normal, see #BM_face_calc_normal.
+ */
+ float no[3];
+ /**
+ * Material index, typically >= 0 and < #Mesh.totcol although this isn't enforced
+ * Python for e.g. can set this to any positive value since scripts may create
+ * mesh data first and setup material slots later.
+ *
+ * When using to index into a material array it's range should be checked first,
+ * values exceeding the range should be ignored or treated as zero
+ * (if a material slot needs to be used - when drawing for e.g.)
+ */
+ short mat_nr;
// short _pad[3];
} BMFace;
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 66f813e02b2..55e349423bb 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -259,12 +259,16 @@ set(SRC
# converter nodes
nodes/COM_CombineColorNode.cc
nodes/COM_CombineColorNode.h
+ nodes/COM_CombineColorNodeLegacy.cc
+ nodes/COM_CombineColorNodeLegacy.h
nodes/COM_CombineXYZNode.cc
nodes/COM_CombineXYZNode.h
nodes/COM_IDMaskNode.cc
nodes/COM_IDMaskNode.h
nodes/COM_SeparateColorNode.cc
nodes/COM_SeparateColorNode.h
+ nodes/COM_SeparateColorNodeLegacy.cc
+ nodes/COM_SeparateColorNodeLegacy.h
nodes/COM_SeparateXYZNode.cc
nodes/COM_SeparateXYZNode.h
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index 13d412a338b..6d7341376e9 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -29,6 +29,7 @@
#include "COM_ColorSpillNode.h"
#include "COM_ColorToBWNode.h"
#include "COM_CombineColorNode.h"
+#include "COM_CombineColorNodeLegacy.h"
#include "COM_CombineXYZNode.h"
#include "COM_CompositorNode.h"
#include "COM_ConvertAlphaNode.h"
@@ -82,6 +83,7 @@
#include "COM_ScaleOperation.h"
#include "COM_SceneTimeNode.h"
#include "COM_SeparateColorNode.h"
+#include "COM_SeparateColorNodeLegacy.h"
#include "COM_SeparateXYZNode.h"
#include "COM_SetAlphaNode.h"
#include "COM_SetValueOperation.h"
@@ -169,28 +171,34 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_BRIGHTCONTRAST:
node = new BrightnessNode(b_node);
break;
- case CMP_NODE_SEPRGBA:
+ case CMP_NODE_SEPARATE_COLOR:
+ node = new SeparateColorNode(b_node);
+ break;
+ case CMP_NODE_COMBINE_COLOR:
+ node = new CombineColorNode(b_node);
+ break;
+ case CMP_NODE_SEPRGBA_LEGACY:
node = new SeparateRGBANode(b_node);
break;
- case CMP_NODE_COMBRGBA:
+ case CMP_NODE_COMBRGBA_LEGACY:
node = new CombineRGBANode(b_node);
break;
- case CMP_NODE_SEPHSVA:
+ case CMP_NODE_SEPHSVA_LEGACY:
node = new SeparateHSVANode(b_node);
break;
- case CMP_NODE_COMBHSVA:
+ case CMP_NODE_COMBHSVA_LEGACY:
node = new CombineHSVANode(b_node);
break;
- case CMP_NODE_SEPYUVA:
+ case CMP_NODE_SEPYUVA_LEGACY:
node = new SeparateYUVANode(b_node);
break;
- case CMP_NODE_COMBYUVA:
+ case CMP_NODE_COMBYUVA_LEGACY:
node = new CombineYUVANode(b_node);
break;
- case CMP_NODE_SEPYCCA:
+ case CMP_NODE_SEPYCCA_LEGACY:
node = new SeparateYCCANode(b_node);
break;
- case CMP_NODE_COMBYCCA:
+ case CMP_NODE_COMBYCCA_LEGACY:
node = new CombineYCCANode(b_node);
break;
case CMP_NODE_ALPHAOVER:
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cc b/source/blender/compositor/nodes/COM_CombineColorNode.cc
index 0c8748fd2d6..ca2c59478fd 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.cc
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc
@@ -12,7 +12,7 @@ CombineColorNode::CombineColorNode(bNode *editor_node) : Node(editor_node)
}
void CombineColorNode::convert_to_operations(NodeConverter &converter,
- const CompositorContext &context) const
+ const CompositorContext &UNUSED(context)) const
{
NodeInput *input_rsocket = this->get_input_socket(0);
NodeInput *input_gsocket = this->get_input_socket(1);
@@ -40,7 +40,39 @@ void CombineColorNode::convert_to_operations(NodeConverter &converter,
converter.map_input_socket(input_bsocket, operation->get_input_socket(2));
converter.map_input_socket(input_asocket, operation->get_input_socket(3));
- NodeOperation *color_conv = get_color_converter(context);
+ bNode *editor_node = this->get_bnode();
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)editor_node->storage;
+
+ NodeOperation *color_conv = nullptr;
+ switch (storage->mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSV: {
+ color_conv = new ConvertHSVToRGBOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSL: {
+ color_conv = new ConvertHSLToRGBOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YCC: {
+ ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
+ operation->set_mode(storage->ycc_mode);
+ color_conv = operation;
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YUV: {
+ color_conv = new ConvertYUVToRGBOperation();
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+
if (color_conv) {
converter.add_operation(color_conv);
@@ -52,27 +84,4 @@ void CombineColorNode::convert_to_operations(NodeConverter &converter,
}
}
-NodeOperation *CombineRGBANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return nullptr; /* no conversion needed */
-}
-
-NodeOperation *CombineHSVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertHSVToRGBOperation();
-}
-
-NodeOperation *CombineYCCANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
- bNode *editor_node = this->get_bnode();
- operation->set_mode(editor_node->custom1);
- return operation;
-}
-
-NodeOperation *CombineYUVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertYUVToRGBOperation();
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.h b/source/blender/compositor/nodes/COM_CombineColorNode.h
index 2bead24cb02..7576cc9eb2d 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.h
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.h
@@ -12,45 +12,6 @@ class CombineColorNode : public Node {
CombineColorNode(bNode *editor_node);
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
-
- protected:
- virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
-};
-
-class CombineRGBANode : public CombineColorNode {
- public:
- CombineRGBANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineHSVANode : public CombineColorNode {
- public:
- CombineHSVANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineYCCANode : public CombineColorNode {
- public:
- CombineYCCANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineYUVANode : public CombineColorNode {
- public:
- CombineYUVANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc
new file mode 100644
index 00000000000..d5ba379bfc2
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#include "COM_CombineColorNodeLegacy.h"
+
+#include "COM_ConvertOperation.h"
+
+namespace blender::compositor {
+
+CombineColorNodeLegacy::CombineColorNodeLegacy(bNode *editor_node) : Node(editor_node)
+{
+}
+
+void CombineColorNodeLegacy::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ NodeInput *input_rsocket = this->get_input_socket(0);
+ NodeInput *input_gsocket = this->get_input_socket(1);
+ NodeInput *input_bsocket = this->get_input_socket(2);
+ NodeInput *input_asocket = this->get_input_socket(3);
+ NodeOutput *output_socket = this->get_output_socket(0);
+
+ CombineChannelsOperation *operation = new CombineChannelsOperation();
+ if (input_rsocket->is_linked()) {
+ operation->set_canvas_input_index(0);
+ }
+ else if (input_gsocket->is_linked()) {
+ operation->set_canvas_input_index(1);
+ }
+ else if (input_bsocket->is_linked()) {
+ operation->set_canvas_input_index(2);
+ }
+ else {
+ operation->set_canvas_input_index(3);
+ }
+ converter.add_operation(operation);
+
+ converter.map_input_socket(input_rsocket, operation->get_input_socket(0));
+ converter.map_input_socket(input_gsocket, operation->get_input_socket(1));
+ converter.map_input_socket(input_bsocket, operation->get_input_socket(2));
+ converter.map_input_socket(input_asocket, operation->get_input_socket(3));
+
+ NodeOperation *color_conv = get_color_converter(context);
+ if (color_conv) {
+ converter.add_operation(color_conv);
+
+ converter.add_link(operation->get_output_socket(), color_conv->get_input_socket(0));
+ converter.map_output_socket(output_socket, color_conv->get_output_socket());
+ }
+ else {
+ converter.map_output_socket(output_socket, operation->get_output_socket());
+ }
+}
+
+NodeOperation *CombineRGBANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return nullptr; /* no conversion needed */
+}
+
+NodeOperation *CombineHSVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertHSVToRGBOperation();
+}
+
+NodeOperation *CombineYCCANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
+ bNode *editor_node = this->get_bnode();
+ operation->set_mode(editor_node->custom1);
+ return operation;
+}
+
+NodeOperation *CombineYUVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertYUVToRGBOperation();
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h
new file mode 100644
index 00000000000..edc66c8932f
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+class CombineColorNodeLegacy : public Node {
+ public:
+ CombineColorNodeLegacy(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+
+ protected:
+ virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
+};
+
+class CombineRGBANode : public CombineColorNodeLegacy {
+ public:
+ CombineRGBANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineHSVANode : public CombineColorNodeLegacy {
+ public:
+ CombineHSVANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineYCCANode : public CombineColorNodeLegacy {
+ public:
+ CombineYCCANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineYUVANode : public CombineColorNodeLegacy {
+ public:
+ CombineYUVANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cc b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
index 221d80e67f2..a956c02ed42 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.cc
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
@@ -12,7 +12,7 @@ SeparateColorNode::SeparateColorNode(bNode *editor_node) : Node(editor_node)
}
void SeparateColorNode::convert_to_operations(NodeConverter &converter,
- const CompositorContext &context) const
+ const CompositorContext &UNUSED(context)) const
{
NodeInput *image_socket = this->get_input_socket(0);
NodeOutput *output_rsocket = this->get_output_socket(0);
@@ -20,7 +20,39 @@ void SeparateColorNode::convert_to_operations(NodeConverter &converter,
NodeOutput *output_bsocket = this->get_output_socket(2);
NodeOutput *output_asocket = this->get_output_socket(3);
- NodeOperation *color_conv = get_color_converter(context);
+ bNode *editor_node = this->get_bnode();
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)editor_node->storage;
+
+ NodeOperation *color_conv = nullptr;
+ switch (storage->mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSV: {
+ color_conv = new ConvertRGBToHSVOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSL: {
+ color_conv = new ConvertRGBToHSLOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YCC: {
+ ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
+ operation->set_mode(storage->ycc_mode);
+ color_conv = operation;
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YUV: {
+ color_conv = new ConvertRGBToYUVOperation();
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+
if (color_conv) {
converter.add_operation(color_conv);
@@ -84,27 +116,4 @@ void SeparateColorNode::convert_to_operations(NodeConverter &converter,
}
}
-NodeOperation *SeparateRGBANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return nullptr; /* no conversion needed */
-}
-
-NodeOperation *SeparateHSVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertRGBToHSVOperation();
-}
-
-NodeOperation *SeparateYCCANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
- bNode *editor_node = this->get_bnode();
- operation->set_mode(editor_node->custom1);
- return operation;
-}
-
-NodeOperation *SeparateYUVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertRGBToYUVOperation();
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.h b/source/blender/compositor/nodes/COM_SeparateColorNode.h
index 78ab0959f43..6adb2d0bb22 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.h
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.h
@@ -12,45 +12,6 @@ class SeparateColorNode : public Node {
SeparateColorNode(bNode *editor_node);
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
-
- protected:
- virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
-};
-
-class SeparateRGBANode : public SeparateColorNode {
- public:
- SeparateRGBANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateHSVANode : public SeparateColorNode {
- public:
- SeparateHSVANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateYCCANode : public SeparateColorNode {
- public:
- SeparateYCCANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateYUVANode : public SeparateColorNode {
- public:
- SeparateYUVANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc
new file mode 100644
index 00000000000..c3728bc152f
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#include "COM_SeparateColorNodeLegacy.h"
+
+#include "COM_ConvertOperation.h"
+
+namespace blender::compositor {
+
+SeparateColorNodeLegacy::SeparateColorNodeLegacy(bNode *editor_node) : Node(editor_node)
+{
+}
+
+void SeparateColorNodeLegacy::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ NodeInput *image_socket = this->get_input_socket(0);
+ NodeOutput *output_rsocket = this->get_output_socket(0);
+ NodeOutput *output_gsocket = this->get_output_socket(1);
+ NodeOutput *output_bsocket = this->get_output_socket(2);
+ NodeOutput *output_asocket = this->get_output_socket(3);
+
+ NodeOperation *color_conv = get_color_converter(context);
+ if (color_conv) {
+ converter.add_operation(color_conv);
+
+ converter.map_input_socket(image_socket, color_conv->get_input_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(0);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_rsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(1);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_gsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(2);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_bsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(3);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_asocket, operation->get_output_socket(0));
+ }
+}
+
+NodeOperation *SeparateRGBANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return nullptr; /* no conversion needed */
+}
+
+NodeOperation *SeparateHSVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertRGBToHSVOperation();
+}
+
+NodeOperation *SeparateYCCANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
+ bNode *editor_node = this->get_bnode();
+ operation->set_mode(editor_node->custom1);
+ return operation;
+}
+
+NodeOperation *SeparateYUVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertRGBToYUVOperation();
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h
new file mode 100644
index 00000000000..10b33039c86
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+class SeparateColorNodeLegacy : public Node {
+ public:
+ SeparateColorNodeLegacy(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+
+ protected:
+ virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
+};
+
+class SeparateRGBANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateRGBANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateHSVANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateHSVANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateYCCANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateYCCANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateYUVANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateYUVANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cc b/source/blender/compositor/operations/COM_ConvertOperation.cc
index 7579abf792a..24c0c577ac7 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cc
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cc
@@ -464,6 +464,68 @@ void ConvertHSVToRGBOperation::update_memory_buffer_partial(BuffersIterator<floa
}
}
+/* ******** RGB to HSL ******** */
+
+ConvertRGBToHSLOperation::ConvertRGBToHSLOperation() : ConvertBaseOperation()
+{
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+}
+
+void ConvertRGBToHSLOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ rgb_to_hsl_v(input_color, output);
+ output[3] = input_color[3];
+}
+
+void ConvertRGBToHSLOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
+{
+ for (; !it.is_end(); ++it) {
+ const float *in = it.in(0);
+ rgb_to_hsl_v(in, it.out);
+ it.out[3] = in[3];
+ }
+}
+
+/* ******** HSL to RGB ******** */
+
+ConvertHSLToRGBOperation::ConvertHSLToRGBOperation() : ConvertBaseOperation()
+{
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+}
+
+void ConvertHSLToRGBOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ hsl_to_rgb_v(input_color, output);
+ output[0] = max_ff(output[0], 0.0f);
+ output[1] = max_ff(output[1], 0.0f);
+ output[2] = max_ff(output[2], 0.0f);
+ output[3] = input_color[3];
+}
+
+void ConvertHSLToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
+{
+ for (; !it.is_end(); ++it) {
+ const float *in = it.in(0);
+ hsl_to_rgb_v(in, it.out);
+ it.out[0] = max_ff(it.out[0], 0.0f);
+ it.out[1] = max_ff(it.out[1], 0.0f);
+ it.out[2] = max_ff(it.out[2], 0.0f);
+ it.out[3] = in[3];
+ }
+}
+
/* ******** Premul to Straight ******** */
ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : ConvertBaseOperation()
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h
index e1904d61d46..16d1e2e6bb5 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.h
+++ b/source/blender/compositor/operations/COM_ConvertOperation.h
@@ -172,6 +172,26 @@ class ConvertHSVToRGBOperation : public ConvertBaseOperation {
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
+class ConvertRGBToHSLOperation : public ConvertBaseOperation {
+ public:
+ ConvertRGBToHSLOperation();
+
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_partial(BuffersIterator<float> &it) override;
+};
+
+class ConvertHSLToRGBOperation : public ConvertBaseOperation {
+ public:
+ ConvertHSLToRGBOperation();
+
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_partial(BuffersIterator<float> &it) override;
+};
+
class ConvertPremulToStraightOperation : public ConvertBaseOperation {
public:
ConvertPremulToStraightOperation();
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index ed90e77572e..f72112d7c54 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -421,8 +421,8 @@ set(GLSL_SRC
intern/shaders/common_subdiv_vbo_lnor_comp.glsl
intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
- intern/draw_shader_shared.h
intern/draw_common_shader_shared.h
+ intern/draw_shader_shared.h
engines/gpencil/shaders/gpencil_frag.glsl
engines/gpencil/shaders/gpencil_vert.glsl
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index 50302eaa87a..161555208f3 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -68,7 +68,7 @@ BLI_INLINE int eevee_cryptomatte_layers_count(const ViewLayer *view_layer)
}
/* The number of render result passes are needed to store a single cryptomatte layer. Per
- * renderpass 2 cryptomatte samples can be stored. */
+ * render-pass 2 cryptomatte samples can be stored. */
BLI_INLINE int eevee_cryptomatte_passes_per_layer(const ViewLayer *view_layer)
{
const int num_cryptomatte_levels = view_layer->cryptomatte_levels;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index ee336326166..3a86640134c 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -301,7 +301,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *maxz_copydepth_ps;
struct DRWPass *maxz_copydepth_layer_ps;
- /* Renderpass Accumulation. */
+ /* Render-pass Accumulation. */
struct DRWPass *material_accum_ps;
struct DRWPass *background_accum_ps;
struct DRWPass *cryptomatte_ps;
@@ -1067,7 +1067,7 @@ typedef struct EEVEE_PrivateData {
GPUTexture *renderpass_col_input;
GPUTexture *renderpass_light_input;
GPUTexture *renderpass_transmittance_input;
- /* Renderpass ubo reference used by material pass. */
+ /* Render-pass UBO reference used by material pass. */
struct GPUUniformBuf *renderpass_ubo;
/** For rendering shadows. */
struct DRWView *cube_views[6];
diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh
index 35eb33671db..7141928a20d 100644
--- a/source/blender/draw/engines/eevee_next/eevee_defines.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh
@@ -11,9 +11,11 @@
#pragma once
-/* Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536. */
-/* Current limiting factor is the sorting phase which is single pass and only sort within a
- * threadgroup which maximum size is 1024. */
+/**
+ Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536.
+ * Current limiting factor is the sorting phase which is single pass and only sort within a
+ * thread-group which maximum size is 1024.
+ */
#define CULLING_BATCH_SIZE 1024
/**
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc
index 922f6c9e1ae..8fef1cf7fc5 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc
@@ -21,9 +21,9 @@
namespace blender::eevee {
/* -------------------------------------------------------------------- */
-/** \name Init
+/** \name Initialization
*
- * Init funcions need to be called once at the start of a frame.
+ * Initialization functions need to be called once at the start of a frame.
* Active camera, render extent and enabled render passes are immutable until next init.
* This takes care of resizing output buffers and view in case a parameter changed.
* IMPORTANT: xxx.init() functions are NOT meant to acquire and allocate DRW resources.
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.hh b/source/blender/draw/engines/eevee_next/eevee_material.hh
index 56f9b077f7a..af9ff6bf6ba 100644
--- a/source/blender/draw/engines/eevee_next/eevee_material.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_material.hh
@@ -104,7 +104,7 @@ static inline eMaterialGeometry to_material_geometry(const Object *ob)
}
}
-/** Unique key to identify each material in the hashmap. */
+/** Unique key to identify each material in the hash-map. */
struct MaterialKey {
Material *mat;
uint64_t options;
@@ -169,7 +169,7 @@ struct ShaderKey {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Default Material Nodetree
+/** \name Default Material Node-Tree
*
* In order to support materials without nodetree we reuse and configure a standalone nodetree that
* we pass for shader generation. The GPUMaterial is still stored inside the Material even if
@@ -254,4 +254,4 @@ class MaterialModule {
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc
index 086c5f9f358..39c5cf6a536 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc
@@ -25,7 +25,7 @@ ShaderModule *ShaderModule::g_shader_module = nullptr;
ShaderModule *ShaderModule::module_get()
{
if (g_shader_module == nullptr) {
- /* TODO(fclem) threadsafety. */
+ /* TODO(@fclem) thread-safety. */
g_shader_module = new ShaderModule();
}
return g_shader_module;
@@ -34,7 +34,7 @@ ShaderModule *ShaderModule::module_get()
void ShaderModule::module_free()
{
if (g_shader_module != nullptr) {
- /* TODO(fclem) threadsafety. */
+ /* TODO(@fclem) thread-safety. */
delete g_shader_module;
g_shader_module = nullptr;
}
@@ -148,7 +148,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
/** Noop. */
break;
case MAT_GEOM_CURVES:
- /** Hair attributes comme from sampler buffer. Transfer attributes to sampler. */
+ /** Hair attributes come from sampler buffer. Transfer attributes to sampler. */
for (auto &input : info.vertex_inputs_) {
if (input.name == "orco") {
/** NOTE: Orco is generated from strand position for now. */
@@ -163,14 +163,14 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
case MAT_GEOM_WORLD:
/**
* Only orco layer is supported by world and it is procedurally generated. These are here to
- * make the attribs_load function calls valids.
+ * make the attribs_load function calls valid.
*/
ATTR_FALLTHROUGH;
case MAT_GEOM_GPENCIL:
/**
* Only one uv and one color attribute layer are supported by gpencil objects and they are
* already declared in another createInfo. These are here to make the attribs_load
- * function calls valids.
+ * function calls valid.
*/
for (auto &input : info.vertex_inputs_) {
global_vars << input.type << " " << input.name << ";\n";
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh
index ba7c97b3b6a..29fcbafb167 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh
@@ -36,7 +36,7 @@ class ShaderModule {
private:
std::array<GPUShader *, MAX_SHADER_TYPE> shaders_;
- /** Shared shader module accross all engine instances. */
+ /** Shared shader module across all engine instances. */
static ShaderModule *g_shader_module;
public:
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
index 2225ccac43a..45b067d203e 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
@@ -27,7 +27,7 @@ using draw::TextureFromPool;
#define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14
/* -------------------------------------------------------------------- */
-/** \name Raytracing
+/** \name Ray-Tracing
* \{ */
enum eClosureBits : uint32_t {
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.hh b/source/blender/draw/engines/eevee_next/eevee_sync.hh
index 51e0f86fe5c..34357193d3e 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.hh
@@ -27,7 +27,7 @@ class Instance;
/* -------------------------------------------------------------------- */
/** \name ObjectKey
*
- * Unique key to identify each object in the hashmap.
+ * Unique key to identify each object in the hash-map.
* \{ */
struct ObjectKey {
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc
index df45200c712..de7341f814b 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_view.cc
@@ -9,7 +9,7 @@
* - The entire main view.
* - A fragment of the main view (for panoramic projections).
* - A shadow map view.
- * - A lightprobe view (either planar, cubemap, irradiance grid).
+ * - A light-probe view (either planar, cube-map, irradiance grid).
*
* A pass is a container for scene data. It is view agnostic but has specific logic depending on
* its type. Passes are shared between views.
@@ -40,7 +40,7 @@ void ShadingView::sync(int2 render_extent_)
int64_t render_pixel_count = render_extent_.x * (int64_t)render_extent_.y;
/* Divide pixel count between the 6 views. Rendering to a square target. */
extent_[0] = extent_[1] = ceilf(sqrtf(1 + (render_pixel_count / 6)));
- /* TODO(fclem) Clip unused views heres. */
+ /* TODO(@fclem): Clip unused views here. */
is_enabled_ = true;
}
else {
@@ -60,8 +60,8 @@ void ShadingView::sync(int2 render_extent_)
const float(*viewmat_p)[4] = viewmat.ptr(), (*winmat_p)[4] = winmat.ptr();
#if 0
if (false /* inst_.camera.is_panoramic() */) {
- /* TODO(fclem) Overscans. */
- /* For now a mandatory 5% overscan for DoF. */
+ /* TODO(@fclem) Over-scans. */
+ /* For now a mandatory 5% over-scan for DoF. */
float side = data.clip_near * 1.05f;
float near = data.clip_near;
float far = data.clip_far;
@@ -205,4 +205,4 @@ void ShadingView::update_view()
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh
index ab7b5722de1..e78a3222d8b 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_view.hh
@@ -8,7 +8,7 @@
* A view is either:
* - The entire main view.
* - A portion of the main view (for panoramic projections).
- * - A lightprobe view (either planar, cubemap, irradiance grid).
+ * - A light-probe view (either planar, cube-map, irradiance grid).
*
* A pass is a container for scene data. It is view agnostic but has specific logic depending on
* its type. Passes are shared between views.
@@ -154,4 +154,4 @@ class MainView {
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_world.hh b/source/blender/draw/engines/eevee_next/eevee_world.hh
index 56554051eea..05177928436 100644
--- a/source/blender/draw/engines/eevee_next/eevee_world.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_world.hh
@@ -18,7 +18,7 @@ namespace blender::eevee {
class Instance;
/* -------------------------------------------------------------------- */
-/** \name Default World Nodetree
+/** \name Default World Node-Tree
*
* In order to support worlds without nodetree we reuse and configure a standalone nodetree that
* we pass for shader generation. The GPUMaterial is still stored inside the World even if
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
index e829a41d682..cd297de5719 100644
--- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
@@ -94,7 +94,7 @@ GPU_SHADER_CREATE_INFO(eevee_surf_forward)
.fragment_source("eevee_surf_forward_frag.glsl")
// .additional_info("eevee_sampling_data",
// "eevee_lightprobe_data",
- /* Optionnally added depending on the material. */
+ /* Optionally added depending on the material. */
// "eevee_raytrace_data",
// "eevee_transmittance_data",
// "eevee_utility_texture",
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index 5c5226bfe65..072d32c41cd 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -124,7 +124,7 @@ void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
}
}
- /* Handles and curve point for Curve Edit submode. */
+ /* Handles and curve point for Curve Edit sub-mode. */
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
DRWState state = DRW_STATE_WRITE_COLOR;
DRW_PASS_CREATE(psl->edit_gpencil_curve_ps, state | pd->clipping_state);
diff --git a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
index a765d881682..b9b1b73dbd4 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
@@ -284,7 +284,7 @@ GPU_SHADER_INTERFACE_INFO(overlay_particle_iface, "").flat(Type::VEC4, "finalCol
GPU_SHADER_CREATE_INFO(overlay_particle)
.sampler(0, ImageType::FLOAT_1D, "weightTex")
- .push_constant(Type::VEC4, "color") /* Drawsize packed in alpha */
+ .push_constant(Type::VEC4, "color") /* Draw-size packed in alpha. */
.vertex_in(0, Type::VEC3, "part_pos")
.vertex_in(1, Type::VEC4, "part_rot")
.vertex_in(2, Type::FLOAT, "part_val")
diff --git a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh b/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
index 713c8c2dc4b..5853e974eeb 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
@@ -48,7 +48,7 @@ GPU_SHADER_CREATE_INFO(overlay_volume_velocity_needle)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Volume Gridlines
+/** \name Volume Grid-Lines
* \{ */
GPU_SHADER_INTERFACE_INFO(overlay_volume_gridlines_iface, "").flat(Type::VEC4, "finalColor");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh b/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
index 43367121d6a..16b59f6bb7d 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
@@ -21,7 +21,7 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe)
.sampler(0, ImageType::DEPTH_2D, "depthTex")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC3, "nor")
- .vertex_in(2, Type::FLOAT, "wd") /* wiredata */
+ .vertex_in(2, Type::FLOAT, "wd") /* wire-data. */
.vertex_out(overlay_wireframe_iface)
.vertex_source("wireframe_vert.glsl")
.fragment_source("wireframe_frag.glsl")
diff --git a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
index ad0de61ffc3..e3166582197 100644
--- a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
+++ b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
@@ -3,7 +3,7 @@
#include "gpu_shader_create_info.hh"
/* -------------------------------------------------------------------- */
-/** \name Select ID fo Edit Mesh selection
+/** \name Select ID for Edit Mesh Selection
* \{ */
GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "id");
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index d803fad5052..6f571084620 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -160,8 +160,8 @@ typedef struct DRWSubdivCache {
/* Contains the start loop index and the smooth flag for each coarse polygon. */
struct GPUVertBuf *extra_coarse_face_data;
- /* Computed for ibo.points, one value per subdivided vertex, mapping coarse vertices ->
- * subdivided loop */
+ /* Computed for `ibo.points`, one value per subdivided vertex,
+ * mapping coarse vertices -> subdivided loop. */
int *point_indices;
/* Material offsets. */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
index 2a4a6a186be..f4c54b2f881 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
@@ -188,7 +188,7 @@ static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
- /* Each element points to an element in the ibo.points. */
+ /* Each element points to an element in the `ibo.points`. */
draw_subdiv_init_origindex_buffer(
vbo,
(int32_t *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index),
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 7bb1d652bf1..c2d517588b2 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -4020,6 +4020,8 @@ static bool acf_nlaaction_setting_valid(bAnimContext *UNUSED(ac),
else {
return false;
}
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return true;
/* unsupported */
default:
@@ -4040,6 +4042,9 @@ static int acf_nlaaction_setting_flag(bAnimContext *UNUSED(ac),
*neg = true; /* XXX */
return ADT_NLA_EDIT_NOMAP;
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
default: /* unsupported */
return 0;
}
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 31d90c8bfec..f148bb5b77d 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -125,6 +125,7 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
@@ -182,6 +183,7 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
@@ -199,7 +201,6 @@ void ANIM_set_active_channel(bAnimContext *ac,
/* unhandled currently, but may be interesting */
case ANIMTYPE_MASKLAYER:
case ANIMTYPE_SHAPEKEY:
- case ANIMTYPE_NLAACTION:
break;
/* other types */
@@ -312,6 +313,7 @@ static eAnimChannels_SetFlag anim_channels_selection_flag_for_toggle(const ListB
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_DSSIMULATION: {
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) {
return ACHANNEL_SETFLAG_CLEAR;
@@ -420,6 +422,7 @@ static void anim_channels_select_set(bAnimContext *ac,
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index b21ae305dbe..791e28de694 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -23,9 +23,9 @@ set(SRC
editcurve.c
editcurve_add.c
editcurve_paint.c
+ editcurve_pen.c
editcurve_query.c
editcurve_select.c
- editcurve_pen.c
editcurve_undo.c
editfont.c
editfont_undo.c
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 9e7e00d5656..d8ecb2c5ae0 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -777,6 +777,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curves.sculpt_cut
ops.curves.sculpt_delete
ops.curves.sculpt_grow_shrink
+ ops.curves.sculpt_puff
ops.curves.sculpt_snake_hook
ops.generic.cursor
ops.generic.select
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 05f9e19da71..cfc158b117f 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -385,24 +385,16 @@ void GEOMETRY_OT_color_attribute_add(wmOperatorType *ot)
ot->srna, "name", "Color", MAX_NAME, "Name", "Name of new color attribute");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- static EnumPropertyItem domains[3] = {{ATTR_DOMAIN_POINT, "POINT", 0, "Vertex", ""},
- {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
- {0, nullptr, 0, nullptr, nullptr}};
-
- static EnumPropertyItem types[3] = {{CD_PROP_COLOR, "COLOR", 0, "Color", ""},
- {CD_PROP_BYTE_COLOR, "BYTE_COLOR", 0, "Byte Color", ""},
- {0, nullptr, 0, nullptr, nullptr}};
-
prop = RNA_def_enum(ot->srna,
"domain",
- domains,
+ rna_enum_color_attribute_domain_items,
ATTR_DOMAIN_POINT,
"Domain",
"Type of element that attribute is stored on");
prop = RNA_def_enum(ot->srna,
"data_type",
- types,
+ rna_enum_color_attribute_type_items,
CD_PROP_COLOR,
"Data Type",
"Type of data stored in attribute");
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 3cdf364e4b2..01ac02a9a1d 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -146,6 +146,10 @@ typedef struct tGP_BrushEditData {
float inv_mat[4][4];
RNG *rng;
+ /* Auto-masking strokes. */
+ struct GHash *automasking_strokes;
+ bool automasking_ready;
+
} tGP_BrushEditData;
/* Callback for performing some brush operation on a single point */
@@ -1182,9 +1186,18 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op)
gso->region = CTX_wm_region(C);
Paint *paint = &ts->gp_sculptpaint->paint;
- gso->brush = paint->brush;
+ Brush *brush = paint->brush;
+ gso->brush = brush;
BKE_curvemapping_init(gso->brush->curve);
+ if (brush->gpencil_settings->sculpt_mode_flag &
+ (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) {
+ gso->automasking_strokes = BLI_ghash_ptr_new(__func__);
+ }
+ else {
+ gso->automasking_strokes = NULL;
+ }
/* save mask */
gso->mask = ts->gpencil_selectmode_sculpt;
@@ -1285,6 +1298,10 @@ static void gpencil_sculpt_brush_exit(bContext *C, wmOperator *op)
BLI_rng_free(gso->rng);
}
+ if (gso->automasking_strokes != NULL) {
+ BLI_ghash_free(gso->automasking_strokes, NULL, NULL);
+ }
+
/* Disable headerprints. */
ED_workspace_status_text(C, NULL);
@@ -1570,11 +1587,15 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
bool redo_geom = false;
Object *ob = gso->object;
bGPdata *gpd = ob->data;
- char tool = gso->brush->gpencil_sculpt_tool;
+ const char tool = gso->brush->gpencil_sculpt_tool;
GP_SpaceConversion *gsc = &gso->gsc;
Brush *brush = gso->brush;
const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
gso->brush->size;
+ const bool is_automasking = (brush->gpencil_settings->sculpt_mode_flag &
+ (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE |
+ GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) != 0;
/* Calc bound box matrix. */
float bound_mat[4][4];
BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
@@ -1589,6 +1610,13 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
continue;
}
+ {
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ if ((is_automasking) && (!BLI_ghash_haskey(gso->automasking_strokes, gps_active))) {
+ continue;
+ }
+ }
+
/* Check if the stroke collide with brush. */
if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
continue;
@@ -1699,6 +1727,132 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
return changed;
}
+/* Get list of Auto-Masking strokes. */
+static bool get_automasking_strokes_list(tGP_BrushEditData *gso)
+{
+ bGPdata *gpd = gso->gpd;
+ GP_SpaceConversion *gsc = &gso->gsc;
+ Brush *brush = gso->brush;
+ Object *ob = gso->object;
+ Material *mat_active = BKE_gpencil_material(ob, ob->actcol);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool is_masking_stroke = (brush->gpencil_settings->sculpt_mode_flag &
+ GP_SCULPT_FLAGMODE_AUTOMASK_STROKE) != 0;
+ const bool is_masking_layer = (brush->gpencil_settings->sculpt_mode_flag &
+ GP_SCULPT_FLAGMODE_AUTOMASK_LAYER) != 0;
+ const bool is_masking_material = (brush->gpencil_settings->sculpt_mode_flag &
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL) != 0;
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+
+ /* Define a fix number of pixel as cursor radius. */
+ const int radius = 10;
+ bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* Only editable and visible layers are considered. */
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* Calculate bound box matrix. */
+ float bound_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
+
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->totpoints == 0) {
+ continue;
+ }
+ /* Check if the color is editable. */
+ if (ED_gpencil_stroke_material_editable(gso->object, gpl, gps) == false) {
+ continue;
+ }
+
+ /* Layer Auto-Masking. */
+ if ((is_masking_layer) && (gpl == gpl_active)) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ continue;
+ }
+ /* Material Auto-Masking. */
+ if (is_masking_material) {
+ Material *mat = BKE_object_material_get(ob, gps->mat_nr + 1);
+ if (mat == mat_active) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ continue;
+ }
+ }
+
+ /* If Stroke Auto-Masking is not enabled, nothing else to do. */
+ if (!is_masking_stroke) {
+ continue;
+ }
+
+ /* Check if the stroke collide with brush. */
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
+ continue;
+ }
+
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ bGPDspoint npt;
+
+ if (gps->totpoints == 1) {
+ gpencil_point_to_parent_space(gps->points, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ /* Only check if point is inside. */
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke.
+ */
+ for (int i = 0; (i + 1) < gps->totpoints; i++) {
+ /* Get points to work with. */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* Check first point. */
+ gpencil_point_to_parent_space(pt1, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ i = gps->totpoints;
+ continue;
+ }
+
+ /* Check second point. */
+ gpencil_point_to_parent_space(pt2, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
+ if (len_v2v2_int(mval_i, pc2) <= radius) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ i = gps->totpoints;
+ continue;
+ }
+
+ /* Check segment. */
+ if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ BLI_ghash_insert(gso->automasking_strokes, gps, gps);
+ i = gps->totpoints;
+ continue;
+ }
+ }
+ }
+ }
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
/* Perform two-pass brushes which modify the existing strokes */
static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
{
@@ -1840,6 +1994,14 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *
gso->brush_rect.xmax = mouse[0] + radius;
gso->brush_rect.ymax = mouse[1] + radius;
+ /* Get list of Auto-Masking strokes. */
+ if ((!gso->automasking_ready) &&
+ (brush->gpencil_settings->sculpt_mode_flag &
+ (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL))) {
+ gso->automasking_ready = get_automasking_strokes_list(gso);
+ }
+
/* Apply brush */
char tool = gso->brush->gpencil_sculpt_tool;
if (tool == GPSCULPT_TOOL_CLONE) {
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 4c01c75e06c..54d36f44f82 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -24,6 +24,7 @@ struct Object;
struct Scene;
struct SpaceImage;
struct ToolSettings;
+struct View2D;
struct ViewLayer;
struct bContext;
struct bNode;
@@ -242,15 +243,12 @@ void uvedit_deselect_flush(const struct Scene *scene, struct BMEditMesh *em);
*/
void uvedit_select_flush(const struct Scene *scene, struct BMEditMesh *em);
-bool ED_uvedit_nearest_uv(const struct Scene *scene,
- struct Object *obedit,
- const float co[2],
- float *dist_sq,
- float r_uv[2]);
-bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
+bool ED_uvedit_nearest_uv_multi(const struct View2D *v2d,
+ const struct Scene *scene,
struct Object **objects,
uint objects_len,
- const float co[2],
+ const int mval[2],
+ const bool ignore_selected,
float *dist_sq,
float r_uv[2]);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 1e9b68c0920..414643dd0d6 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -952,6 +952,22 @@ float ED_view3d_select_dist_px(void);
void ED_view3d_viewcontext_init(struct bContext *C,
struct ViewContext *vc,
struct Depsgraph *depsgraph);
+
+/**
+ * Re-initialize `vc` with `obact` as if it's active object (with some differences).
+ *
+ * This is often used when operating on multiple objects in modes (edit, pose mode etc)
+ * where the `vc` is passed in as an argument which then references it's object data.
+ *
+ * \note members #ViewContext.obedit & #ViewContext.em are only initialized if they're already set,
+ * by #ED_view3d_viewcontext_init in most cases.
+ * This is necessary because the active object defines the current object-mode.
+ * When iterating over objects in object-mode it doesn't make sense to perform
+ * an edit-mode action on an object that happens to contain edit-mode data.
+ * In some cases these values are cleared allowing the owner of `vc` to explicitly
+ * disable edit-mode operation (to force object selection in edit-mode for e.g.).
+ * So object-mode specific values should remain cleared when initialized with another object.
+ */
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
/**
* Use this call when executing an operator,
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9f4d6815287..301171a284d 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -221,7 +221,7 @@ enum {
UI_BUT_HAS_SEP_CHAR = 1 << 27,
/** Don't run updates while dragging (needed in rare cases). */
UI_BUT_UPDATE_DELAY = 1 << 28,
- /** When widget is in textedit mode, update value on each char stroke */
+ /** When widget is in text-edit mode, update value on each char stroke. */
UI_BUT_TEXTEDIT_UPDATE = 1 << 29,
/** Show 'x' icon to clear/unlink value of text or search button. */
UI_BUT_VALUE_CLEAR = 1 << 30,
diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.cc b/source/blender/editors/interface/view2d_gizmo_navigate.cc
index 01729e35246..fae28833e4f 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.cc
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.cc
@@ -130,6 +130,13 @@ static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType *UNUSE
}
break;
}
+ case SPACE_IMAGE: {
+ const SpaceImage *sima = static_cast<const SpaceImage *>(area->spacedata.first);
+ if (sima->gizmo_flag & (SI_GIZMO_HIDE | SI_GIZMO_HIDE_NAVIGATE)) {
+ return false;
+ }
+ break;
+ }
}
return true;
}
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index fd454083653..87923d9fdf8 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -282,6 +282,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->ui = wm_alembic_export_draw;
ot->check = wm_alembic_export_check;
+ ot->flag |= OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
@@ -475,7 +476,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
/* This dummy prop is used to check whether we need to init the start and
* end frame values to that of the scene's, otherwise they are reset at
* every change, draw update. */
- RNA_def_boolean(ot->srna, "init_scene_frame_range", false, "", "");
+ RNA_def_boolean(ot->srna, "init_scene_frame_range", true, "", "");
}
/* ************************************************************************** */
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 2e878770347..d982d86fe77 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1715,7 +1715,7 @@ static int constraint_copy_to_selected_exec(bContext *C, wmOperator *op)
Object *prev_ob = NULL;
- /* Copy all constraints from active posebone to all selected posebones. */
+ /* Copy all constraints from active pose-bone to all selected pose-bones. */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) {
/* If we're not handling the object we're copying from, copy all constraints over. */
if (pchan == chan) {
@@ -2115,7 +2115,7 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
Object *prev_ob = NULL;
- /* copy all constraints from active posebone to all selected posebones */
+ /* Copy all constraints from active pose-bone to all selected pose-bones. */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) {
/* if we're not handling the object we're copying from, copy all constraints over */
if (pchan != chan) {
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index cc6aa34d39d..fdf2cae026d 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -143,7 +143,12 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
}
break;
case OB_CURVES:
- if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT_CURVES)) {
+ if (U.experimental.use_new_curves_tools) {
+ if (mode & OB_MODE_EDIT) {
+ return true;
+ }
+ }
+ if (mode & OB_MODE_SCULPT_CURVES) {
return true;
}
break;
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 08eed52f440..d3bf28798c4 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -27,8 +27,8 @@ set(INC
)
set(SRC
- curves_sculpt_3d_brush.cc
curves_sculpt_add.cc
+ curves_sculpt_brush.cc
curves_sculpt_comb.cc
curves_sculpt_delete.cc
curves_sculpt_grow_shrink.cc
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 0d399419ad8..1fdecf47bbd 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -21,6 +21,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
@@ -107,7 +108,7 @@ struct AddOperationExecutor {
bool use_interpolation_;
float new_curve_length_;
int add_amount_;
- int points_per_curve_ = 8;
+ int points_per_curve_;
/** Various matrices to convert between coordinate spaces. */
float4x4 curves_to_world_mat_;
@@ -171,6 +172,7 @@ struct AddOperationExecutor {
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
add_amount_ = std::max(0, brush_settings_->add_amount);
+ points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
use_interpolation_ = interpolate_length_ || interpolate_shape_;
@@ -183,7 +185,9 @@ struct AddOperationExecutor {
return;
}
- RandomNumberGenerator rng{(uint32_t)(PIL_check_seconds_timer() * 1000000.0f)};
+ const double time = PIL_check_seconds_timer() * 1000000.0;
+ /* Use a pointer cast to avoid overflow warnings. */
+ RandomNumberGenerator rng{*(uint32_t *)(&time)};
BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
@@ -194,13 +198,13 @@ struct AddOperationExecutor {
/* Sample points on the surface using one of multiple strategies. */
AddedPoints added_points;
if (add_amount_ == 1) {
- this->sample_in_center(added_points);
+ this->sample_in_center_with_symmetry(added_points);
}
else if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- this->sample_projected(rng, added_points);
+ this->sample_projected_with_symmetry(rng, added_points);
}
else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->sample_spherical(rng, added_points);
+ this->sample_spherical_with_symmetry(rng, added_points);
}
else {
BLI_assert_unreachable();
@@ -241,13 +245,27 @@ struct AddOperationExecutor {
/**
* Sample a single point exactly at the mouse position.
*/
- void sample_in_center(AddedPoints &r_added_points)
+ void sample_in_center_with_symmetry(AddedPoints &r_added_points)
{
float3 ray_start_wo, ray_end_wo;
ED_view3d_win_to_segment_clipped(
depsgraph_, region_, v3d_, brush_pos_re_, ray_start_wo, ray_end_wo, true);
const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->sample_in_center(
+ r_added_points, brush_transform * ray_start_su, brush_transform * ray_end_su);
+ }
+ }
+
+ void sample_in_center(AddedPoints &r_added_points,
+ const float3 &ray_start_su,
+ const float3 &ray_end_su)
+ {
const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
BVHTreeRayHit ray_hit;
@@ -280,11 +298,23 @@ struct AddOperationExecutor {
/**
* Sample points by shooting rays within the brush radius in the 3D view.
*/
- void sample_projected(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ void sample_projected_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->sample_projected(rng, r_added_points, brush_transform);
+ }
+ }
+
+ void sample_projected(RandomNumberGenerator &rng,
+ AddedPoints &r_added_points,
+ const float4x4 &brush_transform)
{
+ const int old_amount = r_added_points.bary_coords.size();
const int max_iterations = std::max(100'000, add_amount_ * 10);
int current_iteration = 0;
- while (r_added_points.bary_coords.size() < add_amount_) {
+ while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
@@ -296,8 +326,8 @@ struct AddOperationExecutor {
float3 ray_start_wo, ray_end_wo;
ED_view3d_win_to_segment_clipped(
depsgraph_, region_, v3d_, pos_re, ray_start_wo, ray_end_wo, true);
- const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
- const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+ const float3 ray_start_su = brush_transform * (world_to_surface_mat_ * ray_start_wo);
+ const float3 ray_end_su = brush_transform * (world_to_surface_mat_ * ray_end_wo);
const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
BVHTreeRayHit ray_hit;
@@ -339,7 +369,7 @@ struct AddOperationExecutor {
/**
* Sample points in a 3D sphere around the surface position that the mouse hovers over.
*/
- void sample_spherical(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ void sample_spherical_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
{
/* Find ray that starts in the center of the brush. */
float3 brush_ray_start_wo, brush_ray_end_wo;
@@ -347,7 +377,6 @@ struct AddOperationExecutor {
depsgraph_, region_, v3d_, brush_pos_re_, brush_ray_start_wo, brush_ray_end_wo, true);
const float3 brush_ray_start_su = world_to_surface_mat_ * brush_ray_start_wo;
const float3 brush_ray_end_su = world_to_surface_mat_ * brush_ray_end_wo;
- const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
/* Find ray that starts on the boundary of the brush. That is used to compute the brush radius
* in 3D. */
@@ -362,6 +391,27 @@ struct AddOperationExecutor {
const float3 brush_radius_ray_start_su = world_to_surface_mat_ * brush_radius_ray_start_wo;
const float3 brush_radius_ray_end_su = world_to_surface_mat_ * brush_radius_ray_end_wo;
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->sample_spherical(rng,
+ r_added_points,
+ brush_transform * brush_ray_start_su,
+ brush_transform * brush_ray_end_su,
+ brush_transform * brush_radius_ray_start_su,
+ brush_transform * brush_radius_ray_end_su);
+ }
+ }
+
+ void sample_spherical(RandomNumberGenerator &rng,
+ AddedPoints &r_added_points,
+ const float3 &brush_ray_start_su,
+ const float3 &brush_ray_end_su,
+ const float3 &brush_radius_ray_start_su,
+ const float3 &brush_radius_ray_end_su)
+ {
+ const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
+
BVHTreeRayHit ray_hit;
ray_hit.dist = FLT_MAX;
ray_hit.index = -1;
@@ -426,7 +476,8 @@ struct AddOperationExecutor {
const int max_iterations = 5;
int current_iteration = 0;
- while (r_added_points.bary_coords.size() < add_amount_) {
+ const int old_amount = r_added_points.bary_coords.size();
+ while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
@@ -506,8 +557,8 @@ struct AddOperationExecutor {
}
/* Remove samples when there are too many. */
- while (r_added_points.bary_coords.size() > add_amount_) {
- const int index_to_remove = rng.get_int32(r_added_points.bary_coords.size());
+ while (r_added_points.bary_coords.size() > old_amount + add_amount_) {
+ const int index_to_remove = rng.get_int32(add_amount_) + old_amount;
r_added_points.bary_coords.remove_and_reorder(index_to_remove);
r_added_points.looptri_indices.remove_and_reorder(index_to_remove);
r_added_points.positions_cu.remove_and_reorder(index_to_remove);
@@ -786,8 +837,16 @@ void AddOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke
executor.execute(*this, C, stroke_extension);
}
-std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation()
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(bContext &C, ReportList *reports)
{
+ Object &ob_active = *CTX_data_active_object(&C);
+ BLI_assert(ob_active.type == OB_CURVES);
+ Curves &curves_id = *static_cast<Curves *>(ob_active.data);
+ if (curves_id.surface == nullptr || curves_id.surface->type != OB_MESH) {
+ BKE_report(reports, RPT_WARNING, "Can not use Add brush when there is no surface mesh");
+ return {};
+ }
+
return std::make_unique<AddOperation>();
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
index 945bb09c0c6..89470772e1c 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
@@ -116,8 +116,11 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
const float distance_sq_re = math::distance_squared(brush_pos_re, closest_re);
+ float3 brush_position_cu;
+ closest_to_line_segment_v3(brush_position_cu, closest_cu, ray_start_cu, ray_end_cu);
+
BrushPositionCandidate candidate;
- candidate.position_cu = closest_cu;
+ candidate.position_cu = brush_position_cu;
candidate.depth_sq_cu = depth_sq_cu;
candidate.distance_sq_re = distance_sq_re;
@@ -229,4 +232,32 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
return brush_3d;
}
+Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
+{
+ Vector<float4x4> matrices;
+
+ auto symmetry_to_factors = [&](const eCurvesSymmetryType type) -> Span<float> {
+ if (symmetry & type) {
+ static std::array<float, 2> values = {1.0f, -1.0f};
+ return values;
+ }
+ static std::array<float, 1> values = {1.0f};
+ return values;
+ };
+
+ for (const float x : symmetry_to_factors(CURVES_SYMMETRY_X)) {
+ for (const float y : symmetry_to_factors(CURVES_SYMMETRY_Y)) {
+ for (const float z : symmetry_to_factors(CURVES_SYMMETRY_Z)) {
+ float4x4 matrix = float4x4::identity();
+ matrix.values[0][0] = x;
+ matrix.values[1][1] = y;
+ matrix.values[2][2] = z;
+ matrices.append(matrix);
+ }
+ }
+ }
+
+ return matrices;
+}
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
index 232d632aa3f..28258a26f74 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -173,10 +173,10 @@ struct CombOperationExecutor {
EnumerableThreadSpecific<Vector<int>> changed_curves;
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
- this->comb_projected(changed_curves);
+ this->comb_projected_with_symmetry(changed_curves);
}
else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->comb_spherical(changed_curves);
+ this->comb_spherical_with_symmetry(changed_curves);
}
else {
BLI_assert_unreachable();
@@ -192,8 +192,20 @@ struct CombOperationExecutor {
/**
* Do combing in screen space.
*/
- void comb_projected(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
+ void comb_projected_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->comb_projected(r_changed_curves, brush_transform);
+ }
+ }
+
+ void comb_projected(EnumerableThreadSpecific<Vector<int>> &r_changed_curves,
+ const float4x4 &brush_transform)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
@@ -207,7 +219,7 @@ struct CombOperationExecutor {
bool curve_changed = false;
const IndexRange points = curves_->points_for_curve(curve_i);
for (const int point_i : points.drop_front(1)) {
- const float3 old_pos_cu = positions_cu[point_i];
+ const float3 old_pos_cu = brush_transform_inv * positions_cu[point_i];
/* Find the position of the point in screen space. */
float2 old_pos_re;
@@ -232,7 +244,8 @@ struct CombOperationExecutor {
float3 new_position_wo;
ED_view3d_win_to_3d(
v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
- const float3 new_position_cu = world_to_curves_mat_ * new_position_wo;
+ const float3 new_position_cu = brush_transform *
+ (world_to_curves_mat_ * new_position_wo);
positions_cu[point_i] = new_position_cu;
curve_changed = true;
@@ -247,10 +260,8 @@ struct CombOperationExecutor {
/**
* Do combing in 3D space.
*/
- void comb_spherical(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
+ void comb_spherical_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
@@ -268,10 +279,26 @@ struct CombOperationExecutor {
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
- const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
-
const float brush_radius_cu = self_->brush_3d_.radius_cu;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->comb_spherical(r_changed_curves,
+ brush_transform * brush_start_cu,
+ brush_transform * brush_end_cu,
+ brush_radius_cu);
+ }
+ }
+
+ void comb_spherical(EnumerableThreadSpecific<Vector<int>> &r_changed_curves,
+ const float3 &brush_start_cu,
+ const float3 &brush_end_cu,
+ const float brush_radius_cu)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+ const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
Vector<int> &local_changed_curves = r_changed_curves.local();
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
index 2841a19d677..3f3c48ecbb6 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
@@ -117,56 +117,70 @@ struct DeleteOperationExecutor {
}
}
+ Array<bool> curves_to_delete(curves_->curves_num(), false);
if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- this->delete_projected();
+ this->delete_projected_with_symmetry(curves_to_delete);
}
else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->delete_spherical();
+ this->delete_spherical_with_symmetry(curves_to_delete);
}
else {
BLI_assert_unreachable();
}
+ Vector<int64_t> indices;
+ const IndexMask mask = index_mask_ops::find_indices_based_on_predicate(
+ curves_->curves_range(), 4096, indices, [&](const int curve_i) {
+ return curves_to_delete[curve_i];
+ });
+
+ curves_->remove_curves(mask);
+
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
ED_region_tag_redraw(region_);
}
- void delete_projected()
+ void delete_projected_with_symmetry(MutableSpan<bool> curves_to_delete)
{
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->delete_projected(curves_to_delete, brush_transform);
+ }
+ }
+
+ void delete_projected(MutableSpan<bool> curves_to_delete, const float4x4 &brush_transform)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
Span<float3> positions_cu = curves_->positions();
- /* Find indices of curves that have to be removed. */
- Vector<int64_t> indices;
- const IndexMask curves_to_remove = index_mask_ops::find_indices_based_on_predicate(
- curves_->curves_range(), 512, indices, [&](const int curve_i) {
- const IndexRange point_range = curves_->points_for_curve(curve_i);
- for (const int segment_i : IndexRange(point_range.size() - 1)) {
- const float3 pos1_cu = positions_cu[point_range[segment_i]];
- const float3 pos2_cu = positions_cu[point_range[segment_i + 1]];
-
- float2 pos1_re, pos2_re;
- ED_view3d_project_float_v2_m4(region_, pos1_cu, pos1_re, projection.values);
- ED_view3d_project_float_v2_m4(region_, pos2_cu, pos2_re, projection.values);
-
- const float dist = dist_seg_seg_v2(
- pos1_re, pos2_re, brush_pos_prev_re_, brush_pos_re_);
- if (dist <= brush_radius_re_) {
- return true;
- }
+ threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
+ for (const int curve_i : curve_range) {
+ const IndexRange point_range = curves_->points_for_curve(curve_i);
+ for (const int segment_i : IndexRange(point_range.size() - 1)) {
+ const float3 pos1_cu = brush_transform_inv * positions_cu[point_range[segment_i]];
+ const float3 pos2_cu = brush_transform_inv * positions_cu[point_range[segment_i + 1]];
+
+ float2 pos1_re, pos2_re;
+ ED_view3d_project_float_v2_m4(region_, pos1_cu, pos1_re, projection.values);
+ ED_view3d_project_float_v2_m4(region_, pos2_cu, pos2_re, projection.values);
+
+ const float dist = dist_seg_seg_v2(pos1_re, pos2_re, brush_pos_prev_re_, brush_pos_re_);
+ if (dist <= brush_radius_re_) {
+ curves_to_delete[curve_i] = true;
+ break;
}
- return false;
- });
-
- curves_->remove_curves(curves_to_remove);
+ }
+ }
+ });
}
- void delete_spherical()
+ void delete_spherical_with_symmetry(MutableSpan<bool> curves_to_delete)
{
- Span<float3> positions_cu = curves_->positions();
-
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
@@ -184,35 +198,48 @@ struct DeleteOperationExecutor {
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->delete_spherical(
+ curves_to_delete, brush_transform * brush_start_cu, brush_transform * brush_end_cu);
+ }
+ }
+
+ void delete_spherical(MutableSpan<bool> curves_to_delete,
+ const float3 &brush_start_cu,
+ const float3 &brush_end_cu)
+ {
+ Span<float3> positions_cu = curves_->positions();
+
const float brush_radius_cu = self_->brush_3d_.radius_cu;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
- Vector<int64_t> indices;
- const IndexMask curves_to_remove = index_mask_ops::find_indices_based_on_predicate(
- curves_->curves_range(), 512, indices, [&](const int curve_i) {
- const IndexRange points = curves_->points_for_curve(curve_i);
- for (const int segment_i : IndexRange(points.size() - 1)) {
- const float3 pos1_cu = positions_cu[points[segment_i]];
- const float3 pos2_cu = positions_cu[points[segment_i] + 1];
-
- float3 closest_segment_cu, closest_brush_cu;
- isect_seg_seg_v3(pos1_cu,
- pos2_cu,
- brush_start_cu,
- brush_end_cu,
- closest_segment_cu,
- closest_brush_cu);
- const float distance_to_brush_sq_cu = math::distance_squared(closest_segment_cu,
- closest_brush_cu);
- if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
- continue;
- }
- return true;
+ threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
+ for (const int curve_i : curve_range) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int segment_i : IndexRange(points.size() - 1)) {
+ const float3 pos1_cu = positions_cu[points[segment_i]];
+ const float3 pos2_cu = positions_cu[points[segment_i] + 1];
+
+ float3 closest_segment_cu, closest_brush_cu;
+ isect_seg_seg_v3(pos1_cu,
+ pos2_cu,
+ brush_start_cu,
+ brush_end_cu,
+ closest_segment_cu,
+ closest_brush_cu);
+ const float distance_to_brush_sq_cu = math::distance_squared(closest_segment_cu,
+ closest_brush_cu);
+ if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
}
- return false;
- });
-
- curves_->remove_curves(curves_to_remove);
+ curves_to_delete[curve_i] = true;
+ break;
+ }
+ }
+ });
}
void initialize_spherical_brush_reference_point()
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
index 6228a643a76..4ac4559cbbc 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
@@ -367,6 +367,13 @@ struct CurvesEffectOperationExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ Vector<float4x4> symmetry_brush_transforms_inv;
+ for (const float4x4 brush_transform : symmetry_brush_transforms) {
+ symmetry_brush_transforms_inv.append(brush_transform.inverted());
+ }
+
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
Influences &local_influences = influences_for_thread.local();
@@ -374,55 +381,59 @@ struct CurvesEffectOperationExecutor {
const IndexRange points = curves_->points_for_curve(curve_i);
const int tot_segments = points.size() - 1;
float max_move_distance_cu = 0.0f;
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1_cu = positions_cu[points[segment_i]];
- const float3 &p2_cu = positions_cu[points[segment_i] + 1];
-
- float2 p1_re, p2_re;
- ED_view3d_project_float_v2_m4(region_, p1_cu, p1_re, projection.values);
- ED_view3d_project_float_v2_m4(region_, p2_cu, p2_re, projection.values);
-
- float2 closest_on_brush_re;
- float2 closest_on_segment_re;
- float lambda_on_brush;
- float lambda_on_segment;
- const float dist_to_brush_sq_re = closest_seg_seg_v2(closest_on_brush_re,
- closest_on_segment_re,
- &lambda_on_brush,
- &lambda_on_segment,
- brush_pos_start_re_,
- brush_pos_end_re_,
- p1_re,
- p2_re);
-
- if (dist_to_brush_sq_re > brush_radius_sq_re_) {
- continue;
- }
- const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
- const float radius_falloff = BKE_brush_curve_strength(
- brush_, dist_to_brush_re, brush_radius_re_);
- const float weight = brush_strength_ * radius_falloff;
-
- const float3 closest_on_segment_cu = math::interpolate(p1_cu, p2_cu, lambda_on_segment);
-
- float3 brush_start_pos_wo, brush_end_pos_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * closest_on_segment_cu,
- brush_pos_start_re_,
- brush_start_pos_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * closest_on_segment_cu,
- brush_pos_end_re_,
- brush_end_pos_wo);
- const float3 brush_start_pos_cu = world_to_curves_mat_ * brush_start_pos_wo;
- const float3 brush_end_pos_cu = world_to_curves_mat_ * brush_end_pos_wo;
-
- const float move_distance_cu = weight *
- math::distance(brush_start_pos_cu, brush_end_pos_cu);
- max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
+ for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
+ for (const int segment_i : IndexRange(tot_segments)) {
+ const float3 &p1_cu = brush_transform_inv * positions_cu[points[segment_i]];
+ const float3 &p2_cu = brush_transform_inv * positions_cu[points[segment_i] + 1];
+
+ float2 p1_re, p2_re;
+ ED_view3d_project_float_v2_m4(region_, p1_cu, p1_re, projection.values);
+ ED_view3d_project_float_v2_m4(region_, p2_cu, p2_re, projection.values);
+
+ float2 closest_on_brush_re;
+ float2 closest_on_segment_re;
+ float lambda_on_brush;
+ float lambda_on_segment;
+ const float dist_to_brush_sq_re = closest_seg_seg_v2(closest_on_brush_re,
+ closest_on_segment_re,
+ &lambda_on_brush,
+ &lambda_on_segment,
+ brush_pos_start_re_,
+ brush_pos_end_re_,
+ p1_re,
+ p2_re);
+
+ if (dist_to_brush_sq_re > brush_radius_sq_re_) {
+ continue;
+ }
+
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re_);
+ const float weight = brush_strength_ * radius_falloff;
+
+ const float3 closest_on_segment_cu = math::interpolate(
+ p1_cu, p2_cu, lambda_on_segment);
+
+ float3 brush_start_pos_wo, brush_end_pos_wo;
+ ED_view3d_win_to_3d(v3d_,
+ region_,
+ curves_to_world_mat_ * closest_on_segment_cu,
+ brush_pos_start_re_,
+ brush_start_pos_wo);
+ ED_view3d_win_to_3d(v3d_,
+ region_,
+ curves_to_world_mat_ * closest_on_segment_cu,
+ brush_pos_end_re_,
+ brush_end_pos_wo);
+ const float3 brush_start_pos_cu = world_to_curves_mat_ * brush_start_pos_wo;
+ const float3 brush_end_pos_cu = world_to_curves_mat_ * brush_end_pos_wo;
+
+ const float move_distance_cu = weight *
+ math::distance(brush_start_pos_cu, brush_end_pos_cu);
+ max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
+ }
}
if (max_move_distance_cu > 0.0f) {
local_influences.curve_indices.append(curve_i);
@@ -454,6 +465,10 @@ struct CurvesEffectOperationExecutor {
const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu);
const float brush_radius_cu = self_->brush_3d_.radius_cu;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
Influences &local_influences = influences_for_thread.local();
@@ -461,32 +476,37 @@ struct CurvesEffectOperationExecutor {
const IndexRange points = curves_->points_for_curve(curve_i);
const int tot_segments = points.size() - 1;
float max_move_distance_cu = 0.0f;
- for (const int segment_i : IndexRange(tot_segments)) {
- const float3 &p1_cu = positions_cu[points[segment_i]];
- const float3 &p2_cu = positions_cu[points[segment_i] + 1];
-
- float3 closest_on_segment_cu;
- float3 closest_on_brush_cu;
- isect_seg_seg_v3(p1_cu,
- p2_cu,
- brush_pos_start_cu,
- brush_pos_end_cu,
- closest_on_segment_cu,
- closest_on_brush_cu);
-
- const float dist_to_brush_sq_cu = math::distance_squared(closest_on_segment_cu,
- closest_on_brush_cu);
- if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
- continue;
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ const float3 brush_pos_start_transformed_cu = brush_transform * brush_pos_start_cu;
+ const float3 brush_pos_end_transformed_cu = brush_transform * brush_pos_end_cu;
+
+ for (const int segment_i : IndexRange(tot_segments)) {
+ const float3 &p1_cu = positions_cu[points[segment_i]];
+ const float3 &p2_cu = positions_cu[points[segment_i] + 1];
+
+ float3 closest_on_segment_cu;
+ float3 closest_on_brush_cu;
+ isect_seg_seg_v3(p1_cu,
+ p2_cu,
+ brush_pos_start_transformed_cu,
+ brush_pos_end_transformed_cu,
+ closest_on_segment_cu,
+ closest_on_brush_cu);
+
+ const float dist_to_brush_sq_cu = math::distance_squared(closest_on_segment_cu,
+ closest_on_brush_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_radius_cu);
+ const float weight = brush_strength_ * radius_falloff;
+
+ const float move_distance_cu = weight * brush_pos_diff_length_cu;
+ max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
}
-
- const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
- const float radius_falloff = BKE_brush_curve_strength(
- brush_, dist_to_brush_cu, brush_radius_cu);
- const float weight = brush_strength_ * radius_falloff;
-
- const float move_distance_cu = weight * brush_pos_diff_length_cu;
- max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
}
if (max_move_distance_cu > 0.0f) {
local_influences.curve_indices.append(curve_i);
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
index 03413221907..9d000649d62 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -33,7 +33,7 @@ class CurvesSculptStrokeOperation {
virtual void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) = 0;
};
-std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation(bContext &C, ReportList *reports);
std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation();
@@ -53,4 +53,6 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
const float2 &brush_pos_re,
float brush_radius_re);
+Vector<float4x4> get_symmetry_brush_transforms(eCurvesSymmetryType symmetry);
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index 992ac77803a..d8713c8eb1d 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -74,12 +74,12 @@ using blender::bke::CurvesGeometry;
/** \name * SCULPT_CURVES_OT_brush_stroke
* \{ */
-static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bContext *C,
- wmOperator *op)
+static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bContext &C,
+ wmOperator &op)
{
- const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op->ptr, "mode"));
+ const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode"));
- Scene &scene = *CTX_data_scene(C);
+ Scene &scene = *CTX_data_scene(&C);
CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
switch (brush.curves_sculpt_tool) {
@@ -90,9 +90,9 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte
case CURVES_SCULPT_TOOL_SNAKE_HOOK:
return new_snake_hook_operation();
case CURVES_SCULPT_TOOL_ADD:
- return new_add_operation();
+ return new_add_operation(C, op.reports);
case CURVES_SCULPT_TOOL_GROW_SHRINK:
- return new_grow_shrink_operation(mode, C);
+ return new_grow_shrink_operation(mode, &C);
}
BLI_assert_unreachable();
return {};
@@ -131,7 +131,7 @@ static void stroke_update_step(bContext *C,
if (!op_data->operation) {
stroke_extension.is_first = true;
- op_data->operation = start_brush_operation(C, op);
+ op_data->operation = start_brush_operation(*C, *op);
}
else {
stroke_extension.is_first = false;
@@ -149,6 +149,12 @@ static void stroke_done(const bContext *C, PaintStroke *stroke)
static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ if (brush == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
SculptCurvesBrushStrokeData *op_data = MEM_new<SculptCurvesBrushStrokeData>(__func__);
op_data->stroke = paint_stroke_new(C,
op,
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
index 6d930d35f04..d2814c17682 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -136,10 +136,10 @@ struct SnakeHookOperatorExecutor {
}
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
- this->spherical_snake_hook();
+ this->spherical_snake_hook_with_symmetry();
}
else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
- this->projected_snake_hook();
+ this->projected_snake_hook_with_symmetry();
}
else {
BLI_assert_unreachable();
@@ -150,8 +150,19 @@ struct SnakeHookOperatorExecutor {
ED_region_tag_redraw(region_);
}
- void projected_snake_hook()
+ void projected_snake_hook_with_symmetry()
{
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->projected_snake_hook(brush_transform);
+ }
+ }
+
+ void projected_snake_hook(const float4x4 &brush_transform)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
@@ -161,7 +172,7 @@ struct SnakeHookOperatorExecutor {
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
const int last_point_i = points.last();
- const float3 old_pos_cu = positions_cu[last_point_i];
+ const float3 old_pos_cu = brush_transform_inv * positions_cu[last_point_i];
float2 old_pos_re;
ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
@@ -179,17 +190,15 @@ struct SnakeHookOperatorExecutor {
float3 new_position_wo;
ED_view3d_win_to_3d(
v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
- const float3 new_position_cu = world_to_curves_mat_ * new_position_wo;
+ const float3 new_position_cu = brush_transform * (world_to_curves_mat_ * new_position_wo);
this->move_last_point_and_resample(positions_cu.slice(points), new_position_cu);
}
});
}
- void spherical_snake_hook()
+ void spherical_snake_hook_with_symmetry()
{
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
@@ -206,9 +215,23 @@ struct SnakeHookOperatorExecutor {
brush_end_wo);
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
- const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
const float brush_radius_cu = self_->brush_3d_.radius_cu;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->spherical_snake_hook(
+ brush_transform * brush_start_cu, brush_transform * brush_end_cu, brush_radius_cu);
+ }
+ }
+
+ void spherical_snake_hook(const float3 &brush_start_cu,
+ const float3 &brush_end_cu,
+ const float brush_radius_cu)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index 747295f3de0..16b22775b9e 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -4145,13 +4145,7 @@ static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_
}
/**
- * Fills the object's active color atribute layer with the fill color.
- *
- * \param[in] ob: The object.
- * \param[in] fill_color: The fill color.
- * \param[in] only_selected: Limit the fill to selected faces or vertices.
- *
- * \return #true if successful.
+ * See doc-string for #BKE_object_attributes_active_color_fill.
*/
static bool paint_object_attributes_active_color_fill_ex(Object *ob,
ColorPaint4f fill_color,
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 5e4389279eb..f89bfd2a36a 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -107,6 +107,7 @@ bool nla_panel_context(const bContext *C,
found = 1;
break;
}
+ case ANIMTYPE_NLAACTION:
case ANIMTYPE_SCENE: /* Top-Level Widgets doubling up as datablocks */
case ANIMTYPE_OBJECT:
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 958a9fdfc60..d5507619e0d 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -213,6 +213,11 @@ static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
+static void node_buts_combsep_color(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y)
{
if (node->type == NODE_FRAME) {
@@ -480,6 +485,10 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
+ case SH_NODE_COMBINE_COLOR:
+ case SH_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_buts_combsep_color;
+ break;
case SH_NODE_TEX_IMAGE:
ntype->draw_buttons = node_shader_buts_tex_image;
ntype->draw_buttons_ex = node_shader_buts_tex_image_ex;
@@ -589,6 +598,19 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
+static void node_composit_buts_combsep_color(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+ if (storage->mode == CMP_NODE_COMBSEP_COLOR_YCC) {
+ uiItemR(layout, ptr, "ycc_mode", DEFAULT_FLAGS, "", ICON_NONE);
+ }
+}
+
static void node_composit_backdrop_viewer(
SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
{
@@ -821,8 +843,12 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_HUECORRECT:
ntype->draw_buttons = node_composit_buts_huecorrect;
break;
- case CMP_NODE_COMBYCCA:
- case CMP_NODE_SEPYCCA:
+ case CMP_NODE_COMBINE_COLOR:
+ case CMP_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_composit_buts_combsep_color;
+ break;
+ case CMP_NODE_COMBYCCA_LEGACY:
+ case CMP_NODE_SEPYCCA_LEGACY:
ntype->draw_buttons = node_composit_buts_ycc;
break;
case CMP_NODE_MASK_BOX:
@@ -975,6 +1001,11 @@ static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), Poin
uiItemR(layout, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
+static void node_texture_buts_combsep_color(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
/* only once called */
static void node_texture_set_butfunc(bNodeType *ntype)
{
@@ -1020,6 +1051,11 @@ static void node_texture_set_butfunc(bNodeType *ntype)
case TEX_NODE_OUTPUT:
ntype->draw_buttons = node_texture_buts_output;
break;
+
+ case TEX_NODE_COMBINE_COLOR:
+ case TEX_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_texture_buts_combsep_color;
+ break;
}
}
}
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index fae0e4be2a8..59f6bd85d59 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -38,8 +38,8 @@ set(SRC
tree/tree_display_data.cc
tree/tree_display_libraries.cc
tree/tree_display_orphaned.cc
- tree/tree_display_override_library_properties.cc
tree/tree_display_override_library_hierarchies.cc
+ tree/tree_display_override_library_properties.cc
tree/tree_display_scenes.cc
tree/tree_display_sequencer.cc
tree/tree_display_view_layer.cc
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index d898be4eb2c..ff99416c213 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -38,6 +38,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_report.h"
@@ -2504,6 +2505,11 @@ static BIFIconID tree_element_get_icon_from_id(const ID *id)
return ICON_WORKSPACE;
case ID_MSK:
return ICON_MOD_MASK;
+ case ID_NT: {
+ const bNodeTree *ntree = (bNodeTree *)id;
+ const bNodeTreeType *ntreetype = ntree->typeinfo;
+ return (BIFIconID)ntreetype->ui_icon;
+ }
case ID_MC:
return ICON_SEQUENCE;
case ID_PC:
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index b5355efec7a..44f919ca361 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -25,10 +25,10 @@ set(INC
set(SRC
sequencer_add.c
sequencer_buttons.c
- sequencer_drag_drop.c
- sequencer_draw.c
sequencer_channels_draw.c
sequencer_channels_edit.c
+ sequencer_drag_drop.c
+ sequencer_draw.c
sequencer_edit.c
sequencer_modifier.c
sequencer_ops.c
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index ffd33006cc2..7a022441876 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -126,6 +126,7 @@ void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgra
void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
{
vc->obact = obact;
+ /* See public doc-string for rationale on checking the existing values first. */
if (vc->obedit) {
BLI_assert(BKE_object_is_in_editmode(obact));
vc->obedit = obact;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index afad4df2c88..e119b264ae7 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -15,6 +15,7 @@
#include "BLI_math.h"
#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "BKE_context.h"
@@ -25,6 +26,7 @@
#include "RNA_access.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "ED_gizmo_library.h"
@@ -173,20 +175,20 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
return;
}
- UI_GetThemeColor3ubv(TH_TRANSFORM, col);
- col[3] = 128;
-
- UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
- selectedCol[3] = 128;
-
- UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
- activeCol[3] = 192;
-
if (t->spacetype == SPACE_VIEW3D) {
bool draw_target = (t->tsnap.status & TARGET_INIT) &&
(t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
if (draw_target || validSnap(t)) {
+ UI_GetThemeColor3ubv(TH_TRANSFORM, col);
+ col[3] = 128;
+
+ UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
+ selectedCol[3] = 128;
+
+ UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
+ activeCol[3] = 192;
+
const float *loc_cur = NULL;
const float *loc_prev = NULL;
const float *normal = NULL;
@@ -240,8 +242,26 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_IMAGE) {
if (validSnap(t)) {
- /* This will not draw, and I'm nor sure why - campbell */
- /* TODO: see 2.7x for non-working code */
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ float x, y;
+ const float snap_point[2] = {
+ t->tsnap.snapPoint[0] / t->aspect[0],
+ t->tsnap.snapPoint[1] / t->aspect[1],
+ };
+ UI_view2d_view_to_region_fl(&t->region->v2d, UNPACK2(snap_point), &x, &y);
+ float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize;
+
+ GPU_matrix_push_projection();
+ wmOrtho2_region_pixelspace(t->region);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(255, 255, 255);
+ imm_draw_circle_wire_2d(pos, x, y, radius, 8);
+ immUnbindProgram();
+
+ GPU_matrix_pop_projection();
}
}
else if (t->spacetype == SPACE_NODE) {
@@ -990,17 +1010,19 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
{
BLI_assert(t->spacetype == SPACE_IMAGE);
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
- float co[2];
-
- UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
-
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
t->view_layer, NULL, &objects_len);
- float dist_sq = FLT_MAX;
- if (ED_uvedit_nearest_uv_multi(
- t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
+ float dist_sq = square_f((float)SNAP_MIN_DISTANCE);
+ if (ED_uvedit_nearest_uv_multi(&t->region->v2d,
+ t->scene,
+ objects,
+ objects_len,
+ t->mval,
+ true,
+ &dist_sq,
+ t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
t->tsnap.snapPoint[1] *= t->aspect[1];
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 1287804d9ee..13dac431b57 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -1019,8 +1019,13 @@ bool uv_find_nearest_vert_multi(Scene *scene,
return found;
}
-bool ED_uvedit_nearest_uv(
- const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2])
+static bool uvedit_nearest_uv(const Scene *scene,
+ Object *obedit,
+ const float co[2],
+ const float scale[2],
+ const bool ignore_selected,
+ float *dist_sq,
+ float r_uv[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMIter iter;
@@ -1035,8 +1040,14 @@ bool ED_uvedit_nearest_uv(
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
do {
+ if (ignore_selected && uvedit_uv_select_test(scene, l_iter, cd_loop_uv_offset)) {
+ continue;
+ }
+
const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- const float dist_test = len_squared_v2v2(co, uv);
+ float co_tmp[2];
+ mul_v2_v2v2(co_tmp, scale, uv);
+ const float dist_test = len_squared_v2v2(co, co_tmp);
if (dist_best > dist_test) {
dist_best = dist_test;
uv_best = uv;
@@ -1052,17 +1063,27 @@ bool ED_uvedit_nearest_uv(
return false;
}
-bool ED_uvedit_nearest_uv_multi(const Scene *scene,
+bool ED_uvedit_nearest_uv_multi(const View2D *v2d,
+ const Scene *scene,
Object **objects,
const uint objects_len,
- const float co[2],
+ const int mval[2],
+ const bool ignore_selected,
float *dist_sq,
float r_uv[2])
{
bool found = false;
+
+ float scale[2], offset[2];
+ UI_view2d_scale_get(v2d, &scale[0], &scale[1]);
+ UI_view2d_view_to_region_fl(v2d, 0.0f, 0.0f, &offset[0], &offset[1]);
+
+ float co[2];
+ sub_v2_v2v2(co, (float[2]){UNPACK2(mval)}, offset);
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
- if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) {
+ if (uvedit_nearest_uv(scene, obedit, co, scale, ignore_selected, dist_sq, r_uv)) {
found = true;
}
}
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 6108629183c..f87c85f808f 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -65,6 +65,7 @@ set(SRC
# Lineart code
intern/lineart/lineart_chain.c
+ intern/lineart/lineart_cpp_bridge.cc
intern/lineart/lineart_cpu.c
intern/lineart/lineart_ops.c
intern/lineart/lineart_util.c
@@ -74,6 +75,22 @@ set(SRC
)
+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}
+)
+
+list(APPEND LIB
+ ${TBB_LIBRARIES}
+)
+endif()
+
set(LIB
)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index 1058f861be3..0e7df2a136d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -387,7 +387,6 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayout *col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_remove_doubles", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_edge_overlap", 0, IFACE_("Overlapping Edges As Contour"), ICON_NONE);
uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index fcf1e28c6da..259e62a249c 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -122,6 +122,8 @@ static void deformStroke(GpencilModifierData *md,
const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
const bool invert_group = (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0;
const bool use_curve = (mmd->flag & GP_NOISE_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
+ const int cfra = (int)DEG_get_ctime(depsgraph);
+ const bool is_keyframe = (mmd->noise_mode == GP_NOISE_RANDOM_KEYFRAME);
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
@@ -148,7 +150,13 @@ static void deformStroke(GpencilModifierData *md,
seed += BLI_hash_string(md->name);
if (mmd->flag & GP_NOISE_USE_RANDOM) {
- seed += ((int)DEG_get_ctime(depsgraph)) / mmd->step;
+ if (!is_keyframe) {
+ seed += cfra / mmd->step;
+ }
+ else {
+ /* If change every keyframe, use the last keyframe. */
+ seed += gpf->framenum;
+ }
}
/* Sanitize as it can create out of bound reads. */
@@ -302,7 +310,12 @@ static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_random"));
- uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "random_mode", 0, NULL, ICON_NONE);
+
+ const int mode = RNA_enum_get(ptr, "random_mode");
+ if (mode != GP_NOISE_RANDOM_KEYFRAME) {
+ uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
+ }
}
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 5d952991cf7..99107a96cfe 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -132,7 +132,7 @@ typedef struct LineartEdge {
char min_occ;
/** Also for line type determination on chaining. */
- unsigned char flags;
+ uint16_t flags;
unsigned char intersection_mask;
/**
@@ -171,7 +171,7 @@ typedef struct LineartEdgeChainItem {
/** For restoring position to 3d space. */
float gpos[3];
float normal[3];
- unsigned char line_type;
+ uint16_t line_type;
char occlusion;
unsigned char material_mask_bits;
unsigned char intersection_mask;
@@ -189,6 +189,12 @@ typedef struct LineartChainRegisterEntry {
char is_left;
} LineartChainRegisterEntry;
+typedef struct LineartAdjacentEdge {
+ unsigned int v1;
+ unsigned int v2;
+ unsigned int e;
+} LineartAdjacentEdge;
+
enum eLineArtTileRecursiveLimit {
/* If tile gets this small, it's already much smaller than a pixel. No need to continue
* splitting. */
@@ -396,7 +402,7 @@ typedef struct LineartObjectInfo {
typedef struct LineartObjectLoadTaskInfo {
struct LineartRenderBuffer *rb;
- struct Depsgraph *dg;
+ int thread_id;
/* LinkNode styled list */
LineartObjectInfo *pending;
/* Used to spread the load across several threads. This can not overflow. */
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
new file mode 100644
index 00000000000..174399618a5
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cc
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include "BLI_sort.hh"
+#include "BLI_vector.hh"
+#include "MOD_lineart.h"
+#include "lineart_intern.h"
+
+static bool cmp_adjacent_items(const LineartAdjacentEdge &p1, const LineartAdjacentEdge &p2)
+{
+ int a = p1.v1 - p2.v1;
+ int b = p1.v2 - p2.v2;
+ /* parallel_sort() requires cmp() to return true when the first element needs to appear before
+ * the second element in the sorted array, false otherwise (strict weak ordering), see
+ * https://en.cppreference.com/w/cpp/named_req/Compare. */
+ return a < 0 ? true : (a == 0 ? b < 0 : false);
+}
+
+void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length)
+{
+ blender::parallel_sort(ai, ai + length - 1, cmp_adjacent_items);
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 24e11f6be3b..dbe2ae0b890 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -8,6 +8,7 @@
#include "MOD_gpencil_lineart.h"
#include "MOD_lineart.h"
+#include "BLI_edgehash.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -28,6 +29,8 @@
#include "BKE_lib_id.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
@@ -1426,17 +1429,45 @@ static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
}
}
-/**
- * Transform a single vert to it's viewing position.
- */
-static void lineart_vert_transform(
- BMVert *v, int index, LineartVert *RvBuf, double (*mv_mat)[4], double (*mvp_mat)[4])
+typedef struct LineartEdgeNeighbor {
+ int e;
+ uint16_t flags;
+ int v1, v2;
+} LineartEdgeNeighbor;
+
+typedef struct VertData {
+ MVert *mvert;
+ LineartVert *v_arr;
+ double (*model_view)[4];
+ double (*model_view_proj)[4];
+} VertData;
+
+static void lineart_mvert_transform_task(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
+ VertData *vert_task_data = (VertData *)userdata;
+ MVert *m_v = &vert_task_data->mvert[i];
double co[4];
- LineartVert *vt = &RvBuf[index];
- copy_v3db_v3fl(co, v->co);
- mul_v3_m4v3_db(vt->gloc, mv_mat, co);
- mul_v4_m4v3_db(vt->fbcoord, mvp_mat, co);
+ LineartVert *v = &vert_task_data->v_arr[i];
+ copy_v3db_v3fl(co, m_v->co);
+ mul_v3_m4v3_db(v->gloc, vert_task_data->model_view, co);
+ mul_v4_m4v3_db(v->fbcoord, vert_task_data->model_view_proj, co);
+ v->index = i;
+}
+
+#define LRT_EDGE_FLAG_TYPE_MAX_BITS 6
+
+static int lineart_edge_type_duplication_count(char eflag)
+{
+ int count = 0;
+ /* See eLineartEdgeFlag for details. */
+ for (int i = 0; i < LRT_EDGE_FLAG_TYPE_MAX_BITS; i++) {
+ if (eflag & (1 << i)) {
+ count++;
+ }
+ }
+ return count;
}
/**
@@ -1452,88 +1483,123 @@ static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb,
return (LineartTriangle *)b;
}
-static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
- BMEdge *e,
- LineartTriangle *rt_array,
- LineartVert *rv_array,
- float crease_threshold,
- bool use_auto_smooth,
- bool use_freestyle_edge,
- bool use_freestyle_face,
- BMesh *bm_if_freestyle)
+typedef struct EdgeFeatData {
+ LineartRenderBuffer *rb;
+ Mesh *me;
+ const MLoopTri *mlooptri;
+ LineartTriangle *tri_array;
+ LineartVert *v_array;
+ float crease_threshold;
+ bool use_auto_smooth;
+ bool use_freestyle_face;
+ int freestyle_face_index;
+ bool use_freestyle_edge;
+ int freestyle_edge_index;
+ LineartEdgeNeighbor *edge_nabr;
+} EdgeFeatData;
+
+typedef struct EdgeFeatReduceData {
+ int feat_edges;
+} EdgeFeatReduceData;
+
+static void feat_data_sum_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- BMLoop *ll, *lr = NULL;
+ EdgeFeatReduceData *feat_chunk_join = (EdgeFeatReduceData *)chunk_join;
+ EdgeFeatReduceData *feat_chunk = (EdgeFeatReduceData *)chunk;
+ feat_chunk_join->feat_edges += feat_chunk->feat_edges;
+}
- ll = e->l;
- if (ll) {
- lr = e->l->radial_next;
- }
+static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict tls)
+{
+ EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata;
+ EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk;
+ Mesh *me = e_feat_data->me;
+ LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr;
+ const MLoopTri *mlooptri = e_feat_data->mlooptri;
- if (!ll && !lr) {
- return LRT_EDGE_FLAG_LOOSE;
+ uint16_t edge_flag_result = 0;
+
+ /* Because the edge neighbor array contains loop edge pairs, we only need to process the first
+ * edge in the pair. Otherwise we would add the same edge that the loops represent twice. */
+ if (i < edge_nabr[i].e) {
+ return;
}
- FreestyleEdge *fel, *fer;
bool face_mark_filtered = false;
- uint16_t edge_flag_result = 0;
+ bool enable_face_mark = (e_feat_data->use_freestyle_face && e_feat_data->rb->filter_face_mark);
bool only_contour = false;
-
- if (use_freestyle_face && rb->filter_face_mark) {
- fel = CustomData_bmesh_get(&bm_if_freestyle->pdata, ll->f->head.data, CD_FREESTYLE_FACE);
- if (ll != lr && lr) {
- fer = CustomData_bmesh_get(&bm_if_freestyle->pdata, lr->f->head.data, CD_FREESTYLE_FACE);
+ if (enable_face_mark) {
+ FreestyleFace *ff1, *ff2;
+ int index = e_feat_data->freestyle_face_index;
+ if (index > -1) {
+ ff1 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[i / 3].poly];
+ }
+ if (edge_nabr[i].e > -1) {
+ ff2 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[edge_nabr[i].e / 3].poly];
}
else {
- /* Handles mesh boundary case */
- fer = fel;
+ /* Handle mesh boundary cases: We want mesh boundaries to respect
+ * `filter_face_mark_boundaries` option the same way as face mark boundaries, and the code
+ * path is simper when it's assuming both ff1 and ff2 not NULL. */
+ ff2 = ff1;
}
- if (rb->filter_face_mark_boundaries ^ rb->filter_face_mark_invert) {
- if ((fel->flag & FREESTYLE_FACE_MARK) || (fer->flag & FREESTYLE_FACE_MARK)) {
+ if (e_feat_data->rb->filter_face_mark_boundaries ^ e_feat_data->rb->filter_face_mark_invert) {
+ if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) {
face_mark_filtered = true;
}
}
else {
- if ((fel->flag & FREESTYLE_FACE_MARK) && (fer->flag & FREESTYLE_FACE_MARK) && (fer != fel)) {
+ if ((ff1->flag & FREESTYLE_FACE_MARK) && (ff2->flag & FREESTYLE_FACE_MARK) && (ff2 != ff1)) {
face_mark_filtered = true;
}
}
- if (rb->filter_face_mark_invert) {
+ if (e_feat_data->rb->filter_face_mark_invert) {
face_mark_filtered = !face_mark_filtered;
}
if (!face_mark_filtered) {
- if (rb->filter_face_mark_keep_contour) {
+ edge_nabr[i].flags = LRT_EDGE_FLAG_INHIBIT;
+ if (e_feat_data->rb->filter_face_mark_keep_contour) {
only_contour = true;
}
- else {
- return 0;
- }
}
}
+ if (enable_face_mark && !face_mark_filtered && !only_contour) {
+ return;
+ }
+
/* Mesh boundary */
- if (!lr || ll == lr) {
- return (edge_flag_result | LRT_EDGE_FLAG_CONTOUR);
+ if (edge_nabr[i].e == -1) {
+ edge_nabr[i].flags = LRT_EDGE_FLAG_CONTOUR;
+ reduce_data->feat_edges += 1;
+ return;
}
LineartTriangle *tri1, *tri2;
- LineartVert *l;
+ LineartVert *vert;
+ LineartRenderBuffer *rb = e_feat_data->rb;
+
+ int f1 = i / 3, f2 = edge_nabr[i].e / 3;
/* The mesh should already be triangulated now, so we can assume each face is a triangle. */
- tri1 = lineart_triangle_from_index(rb, rt_array, BM_elem_index_get(ll->f));
- tri2 = lineart_triangle_from_index(rb, rt_array, BM_elem_index_get(lr->f));
+ tri1 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f1);
+ tri2 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f2);
- l = &rv_array[BM_elem_index_get(e->v1)];
+ vert = &e_feat_data->v_array[edge_nabr[i].v1];
- double vv[3];
- double *view_vector = vv;
+ double view_vector_persp[3];
+ double *view_vector = view_vector_persp;
double dot_1 = 0, dot_2 = 0;
double result;
bool material_back_face = ((tri1->flags | tri2->flags) & LRT_TRIANGLE_MAT_BACK_FACE_CULLING);
if (rb->use_contour || rb->use_back_face_culling || material_back_face) {
-
if (rb->cam_is_persp) {
- sub_v3_v3v3_db(view_vector, rb->camera_pos, l->gloc);
+ sub_v3_v3v3_db(view_vector, rb->camera_pos, vert->gloc);
}
else {
view_vector = rb->view_vector;
@@ -1542,11 +1608,10 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
dot_1 = dot_v3v3_db(view_vector, tri1->gn);
dot_2 = dot_v3v3_db(view_vector, tri2->gn);
- if (rb->use_contour && (result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
- /* Because the ray points towards the camera, so back-face is when dot value being negative. */
if (rb->use_back_face_culling) {
if (dot_1 < 0) {
tri1->flags |= LRT_CULL_DISCARD;
@@ -1564,56 +1629,129 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
}
}
}
- else {
- view_vector = rb->view_vector;
- }
- if ((result = dot_1 * dot_2) <= 0 && (fabs(dot_1) + fabs(dot_2))) {
- edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
- }
+ if (!only_contour) {
- /* For when face mark filtering decided that we discard the face but keep_contour option is on.
- * so we still have correct full contour around the object. */
- if (only_contour) {
- return edge_flag_result;
- }
+ if (rb->use_crease) {
+ bool do_crease = true;
+ if (!rb->force_crease && !e_feat_data->use_auto_smooth &&
+ (me->mpoly[mlooptri[f1].poly].flag & ME_SMOOTH) &&
+ (me->mpoly[mlooptri[f2].poly].flag & ME_SMOOTH)) {
+ do_crease = false;
+ }
+ if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < e_feat_data->crease_threshold)) {
+ edge_flag_result |= LRT_EDGE_FLAG_CREASE;
+ }
+ }
- /* Do not show lines other than contour on back face (because contour has one adjacent face that
- * isn't a back face).
- * TODO(Yiming): Do we need separate option for this? */
- if (rb->use_back_face_culling ||
- ((tri1->flags & tri2->flags) & LRT_TRIANGLE_MAT_BACK_FACE_CULLING)) {
- if (dot_1 < 0 && dot_2 < 0) {
- return edge_flag_result;
+ int mat1 = me->mpoly[mlooptri[f1].poly].mat_nr;
+ int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr;
+
+ if (rb->use_material && mat1 != mat2) {
+ edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
+ }
+ }
+ else { /* only_contour */
+ if (!edge_flag_result) { /* Other edge types inhibited */
+ return;
}
}
- if (rb->use_crease) {
- if (rb->sharp_as_crease && !BM_elem_flag_test(e, BM_ELEM_SMOOTH)) {
+ int real_edges[3];
+ BKE_mesh_looptri_get_real_edges(me, &mlooptri[i / 3], real_edges);
+
+ if (real_edges[i % 3] >= 0) {
+ MEdge *medge = &me->medge[real_edges[i % 3]];
+
+ if (rb->use_crease && rb->sharp_as_crease && (medge->flag & ME_SHARP)) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
}
- else {
- bool do_crease = true;
- if (!rb->force_crease && !use_auto_smooth &&
- (BM_elem_flag_test(ll->f, BM_ELEM_SMOOTH) && BM_elem_flag_test(lr->f, BM_ELEM_SMOOTH))) {
- do_crease = false;
- }
- if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < crease_threshold)) {
- edge_flag_result |= LRT_EDGE_FLAG_CREASE;
+
+ if (rb->use_edge_marks && e_feat_data->use_freestyle_edge) {
+ FreestyleEdge *fe;
+ int index = e_feat_data->freestyle_edge_index;
+ fe = &((FreestyleEdge *)me->edata.layers[index].data)[real_edges[i % 3]];
+ if (fe->flag & FREESTYLE_EDGE_MARK) {
+ edge_flag_result |= LRT_EDGE_FLAG_EDGE_MARK;
}
}
}
- if (rb->use_material && (ll->f->mat_nr != lr->f->mat_nr)) {
- edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
+
+ edge_nabr[i].flags = edge_flag_result;
+
+ if (edge_flag_result) {
+ /* Only allocate for feature edge (instead of all edges) to save memory.
+ * If allow duplicated edges, one edge gets added multiple times if it has multiple types.
+ */
+ reduce_data->feat_edges += e_feat_data->rb->allow_duplicated_types ?
+ lineart_edge_type_duplication_count(edge_flag_result) :
+ 1;
}
- if (use_freestyle_edge && rb->use_edge_marks) {
- FreestyleEdge *fe;
- fe = CustomData_bmesh_get(&bm_if_freestyle->edata, e->head.data, CD_FREESTYLE_EDGE);
- if (fe->flag & FREESTYLE_EDGE_MARK) {
- edge_flag_result |= LRT_EDGE_FLAG_EDGE_MARK;
- }
+}
+
+typedef struct LooseEdgeData {
+ int loose_count;
+ int loose_max;
+ MEdge **loose_array;
+ Mesh *me;
+} LooseEdgeData;
+
+static void lineart_loose_data_reallocate(LooseEdgeData *loose_data, int count)
+{
+ MEdge **new_arr = MEM_callocN(sizeof(MEdge *) * count, "loose edge array");
+ if (loose_data->loose_array) {
+ memcpy(new_arr, loose_data->loose_array, sizeof(MEdge *) * loose_data->loose_max);
+ MEM_freeN(loose_data->loose_array);
+ }
+ loose_data->loose_max = count;
+ loose_data->loose_array = new_arr;
+}
+
+static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData *to_be_joined)
+{
+ if (!to_be_joined->loose_array) {
+ return;
+ }
+ int new_count = loose_data->loose_count + to_be_joined->loose_count;
+ if (new_count >= loose_data->loose_max) {
+ lineart_loose_data_reallocate(loose_data, new_count);
+ }
+ memcpy(&loose_data->loose_array[loose_data->loose_count],
+ to_be_joined->loose_array,
+ sizeof(MEdge *) * to_be_joined->loose_count);
+ loose_data->loose_count += to_be_joined->loose_count;
+ MEM_freeN(to_be_joined->loose_array);
+}
+
+static void lineart_add_loose_edge(LooseEdgeData *loose_data, MEdge *e)
+{
+ if (loose_data->loose_count >= loose_data->loose_max) {
+ int min_amount = MAX2(100, loose_data->loose_count * 2);
+ lineart_loose_data_reallocate(loose_data, min_amount);
}
- return edge_flag_result;
+ loose_data->loose_array[loose_data->loose_count] = e;
+ loose_data->loose_count++;
+}
+
+static void lineart_identify_loose_edges(void *__restrict UNUSED(userdata),
+ const int i,
+ const TaskParallelTLS *__restrict tls)
+{
+ LooseEdgeData *loose_data = (LooseEdgeData *)tls->userdata_chunk;
+ Mesh *me = loose_data->me;
+
+ if (me->medge[i].flag & ME_LOOSEEDGE) {
+ lineart_add_loose_edge(loose_data, &me->medge[i]);
+ }
+}
+
+static void loose_data_sum_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ LooseEdgeData *final = (LooseEdgeData *)chunk_join;
+ LooseEdgeData *loose_chunk = (LooseEdgeData *)chunk;
+ lineart_join_loose_edge_arr(final, loose_chunk);
}
static void lineart_add_edge_to_list(LineartRenderBuffer *rb, LineartEdge *e)
@@ -1702,298 +1840,421 @@ static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
}
}
-static int lineart_edge_type_duplication_count(char eflag)
+typedef struct TriData {
+ LineartObjectInfo *ob_info;
+ const MLoopTri *mlooptri;
+ LineartVert *vert_arr;
+ LineartTriangle *tri_arr;
+ int lineart_triangle_size;
+ LineartTriangleAdjacent *tri_adj;
+} TriData;
+
+static void lineart_load_tri_task(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
- int count = 0;
- /* See eLineartEdgeFlag for details. */
- for (int i = 0; i < 6; i++) {
- if (eflag & (1 << i)) {
- count++;
- }
- }
- return count;
+ TriData *tri_task_data = (TriData *)userdata;
+ Mesh *me = tri_task_data->ob_info->original_me;
+ LineartObjectInfo *ob_info = tri_task_data->ob_info;
+ const MLoopTri *mlooptri = &tri_task_data->mlooptri[i];
+ LineartVert *vert_arr = tri_task_data->vert_arr;
+ LineartTriangle *tri = tri_task_data->tri_arr;
+
+ tri = (LineartTriangle *)(((uchar *)tri) + tri_task_data->lineart_triangle_size * i);
+
+ int v1 = me->mloop[mlooptri->tri[0]].v;
+ int v2 = me->mloop[mlooptri->tri[1]].v;
+ int v3 = me->mloop[mlooptri->tri[2]].v;
+
+ tri->v[0] = &vert_arr[v1];
+ tri->v[1] = &vert_arr[v2];
+ tri->v[2] = &vert_arr[v3];
+
+ /* Material mask bits and occlusion effectiveness assignment. */
+ Material *mat = BKE_object_material_get(ob_info->original_ob,
+ me->mpoly[mlooptri->poly].mat_nr + 1);
+ tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ?
+ mat->lineart.material_mask_bits :
+ 0);
+ tri->mat_occlusion |= (mat ? mat->lineart.mat_occlusion : 1);
+ tri->flags |= (mat && (mat->blend_flag & MA_BL_CULL_BACKFACE)) ?
+ LRT_TRIANGLE_MAT_BACK_FACE_CULLING :
+ 0;
+
+ tri->intersection_mask = ob_info->override_intersection_mask;
+
+ double gn[3];
+ float no[3];
+ normal_tri_v3(no, me->mvert[v1].co, me->mvert[v2].co, me->mvert[v3].co);
+ copy_v3db_v3fl(gn, no);
+ mul_v3_mat3_m4v3_db(tri->gn, ob_info->normal, gn);
+ normalize_v3_db(tri->gn);
+
+ if (ob_info->usage == OBJECT_LRT_INTERSECTION_ONLY) {
+ tri->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
+ }
+ else if (ob_info->usage == OBJECT_LRT_NO_INTERSECTION ||
+ ob_info->usage == OBJECT_LRT_OCCLUSION_ONLY) {
+ tri->flags |= LRT_TRIANGLE_NO_INTERSECTION;
+ }
+
+ /* Re-use this field to refer to adjacent info, will be cleared after culling stage. */
+ tri->intersecting_verts = (void *)&tri_task_data->tri_adj[i];
}
-static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBuffer *rb)
+typedef struct EdgeNeighborData {
+ LineartEdgeNeighbor *edge_nabr;
+ LineartAdjacentEdge *adj_e;
+ MLoopTri *mlooptri;
+ MLoop *mloop;
+} EdgeNeighborData;
+
+static void lineart_edge_neighbor_init_task(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
- BMesh *bm;
- BMVert *v;
- BMFace *f;
- BMEdge *e;
- BMLoop *loop;
- LineartEdge *la_e;
- LineartEdgeSegment *la_s;
- LineartTriangle *tri;
- LineartTriangleAdjacent *orta;
- double(*model_view_proj)[4] = obi->model_view_proj, (*model_view)[4] = obi->model_view,
- (*normal)[4] = obi->normal;
- LineartElementLinkNode *eln;
- LineartVert *orv;
- LineartEdge *o_la_e;
- LineartEdgeSegment *o_la_s;
- LineartTriangle *ort;
- Object *orig_ob;
- bool can_find_freestyle_edge = false;
- bool can_find_freestyle_face = false;
- int i;
- float use_crease = 0;
+ EdgeNeighborData *en_data = (EdgeNeighborData *)userdata;
+ LineartAdjacentEdge *adj_e = &en_data->adj_e[i];
+ MLoopTri *looptri = &en_data->mlooptri[i / 3];
+ LineartEdgeNeighbor *edge_nabr = &en_data->edge_nabr[i];
+ MLoop *mloop = en_data->mloop;
+
+ adj_e->e = i;
+ adj_e->v1 = mloop[looptri->tri[i % 3]].v;
+ adj_e->v2 = mloop[looptri->tri[(i + 1) % 3]].v;
+ if (adj_e->v1 > adj_e->v2) {
+ SWAP(unsigned int, adj_e->v1, adj_e->v2);
+ }
+ edge_nabr->e = -1;
+
+ edge_nabr->v1 = adj_e->v1;
+ edge_nabr->v2 = adj_e->v2;
+ edge_nabr->flags = 0;
+}
- int usage = obi->usage;
+static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edges)
+{
+ /* Because the mesh is triangulated, so `me->totedge` should be reliable? */
+ LineartAdjacentEdge *adj_e = MEM_mallocN(sizeof(LineartAdjacentEdge) * total_edges,
+ "LineartAdjacentEdge arr");
+ LineartEdgeNeighbor *edge_nabr = MEM_mallocN(sizeof(LineartEdgeNeighbor) * total_edges,
+ "LineartEdgeNeighbor arr");
- if (obi->original_me->edit_mesh) {
- /* Do not use edit_mesh directly because we will modify it, so create a copy. */
- bm = BM_mesh_copy(obi->original_me->edit_mesh->bm);
- }
- else {
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(((Mesh *)(obi->original_me)));
- bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
- BM_mesh_bm_from_me(bm,
- obi->original_me,
- &((struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .calc_vert_normal = true,
- }));
- }
+ MLoopTri *mlooptri = me->runtime.looptris.array;
- if (obi->free_use_mesh) {
- BKE_id_free(NULL, obi->original_me);
- }
+ TaskParallelSettings en_settings;
+ BLI_parallel_range_settings_defaults(&en_settings);
+ /* Set the minimum amount of edges a thread has to process. */
+ en_settings.min_iter_per_thread = 50000;
+
+ EdgeNeighborData en_data;
+ en_data.adj_e = adj_e;
+ en_data.edge_nabr = edge_nabr;
+ en_data.mlooptri = mlooptri;
+ en_data.mloop = me->mloop;
- if (rb->remove_doubles) {
- BMEditMesh *em = BKE_editmesh_create(bm);
- BMOperator findop, weldop;
+ BLI_task_parallel_range(0, total_edges, &en_data, lineart_edge_neighbor_init_task, &en_settings);
- /* See bmesh_opdefines.c and bmesh_operators.c for op names and argument formatting. */
- BMO_op_initf(bm, &findop, BMO_FLAG_DEFAULTS, "find_doubles verts=%av dist=%f", 0.0001);
+ lineart_sort_adjacent_items(adj_e, total_edges);
- BMO_op_exec(bm, &findop);
+ for (int i = 0; i < total_edges - 1; i++) {
+ if (adj_e[i].v1 == adj_e[i + 1].v1 && adj_e[i].v2 == adj_e[i + 1].v2) {
+ edge_nabr[adj_e[i].e].e = adj_e[i + 1].e;
+ edge_nabr[adj_e[i + 1].e].e = adj_e[i].e;
+ }
+ }
- /* Weld the vertices. */
- BMO_op_init(bm, &weldop, BMO_FLAG_DEFAULTS, "weld_verts");
- BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap");
- BMO_op_exec(bm, &weldop);
+ MEM_freeN(adj_e);
+
+ return edge_nabr;
+}
+
+static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRenderBuffer *re_buf)
+{
+ LineartElementLinkNode *elem_link_node;
+ LineartVert *la_v_arr;
+ LineartEdge *la_edge_arr;
+ LineartEdgeSegment *la_seg_arr;
+ LineartTriangle *la_tri_arr;
- BMO_op_finish(bm, &findop);
- BMO_op_finish(bm, &weldop);
+ Mesh *me = ob_info->original_me;
- MEM_freeN(em);
+ if (!me->totedge) {
+ return;
}
- BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false);
- BM_mesh_triangulate(
- bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_BEAUTY, 4, false, NULL, NULL, NULL);
- BM_mesh_normals_update(bm);
- BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
- BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
+ /* Triangulate. */
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
+ const int tot_tri = BKE_mesh_runtime_looptri_len(me);
- if (CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
- can_find_freestyle_edge = 1;
+ /* Check if we should look for custom data tags like Freestyle edges or faces. */
+ bool can_find_freestyle_edge = false;
+ int layer_index = CustomData_get_active_layer_index(&me->edata, CD_FREESTYLE_EDGE);
+ if (layer_index != -1) {
+ can_find_freestyle_edge = true;
}
- if (CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) {
+
+ bool can_find_freestyle_face = false;
+ layer_index = CustomData_get_active_layer_index(&me->pdata, CD_FREESTYLE_FACE);
+ if (layer_index != -1) {
can_find_freestyle_face = true;
}
/* If we allow duplicated edges, one edge should get added multiple times if is has been
* classified as more than one edge type. This is so we can create multiple different line type
* chains containing the same edge. */
- orv = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartVert) * bm->totvert);
- ort = lineart_mem_acquire_thread(&rb->render_data_pool, bm->totface * rb->triangle_size);
+ la_v_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ sizeof(LineartVert) * me->totvert);
+ la_tri_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ tot_tri * re_buf->triangle_size);
- orig_ob = obi->original_ob;
+ Object *orig_ob = ob_info->original_ob;
- BLI_spin_lock(&rb->lock_task);
- eln = lineart_list_append_pointer_pool_sized_thread(
- &rb->vertex_buffer_pointers, &rb->render_data_pool, orv, sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&rb->lock_task);
+ BLI_spin_lock(&re_buf->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->vertex_buffer_pointers,
+ &re_buf->render_data_pool,
+ la_v_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&re_buf->lock_task);
- eln->element_count = bm->totvert;
- eln->object_ref = orig_ob;
- obi->v_eln = eln;
+ elem_link_node->element_count = me->totvert;
+ elem_link_node->object_ref = orig_ob;
+ ob_info->v_eln = elem_link_node;
bool use_auto_smooth = false;
+ float crease_angle = 0;
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
- use_crease = cosf(M_PI - orig_ob->lineart.crease_threshold);
+ crease_angle = cosf(M_PI - orig_ob->lineart.crease_threshold);
}
- else if (obi->original_me->flag & ME_AUTOSMOOTH) {
- use_crease = cosf(obi->original_me->smoothresh);
+ else if (ob_info->original_me->flag & ME_AUTOSMOOTH) {
+ crease_angle = cosf(ob_info->original_me->smoothresh);
use_auto_smooth = true;
}
else {
- use_crease = rb->crease_threshold;
+ crease_angle = re_buf->crease_threshold;
}
/* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
* erroneous detection on creases. Future configuration should allow options. */
if (orig_ob->type == OB_FONT) {
- eln->flags |= LRT_ELEMENT_BORDER_ONLY;
+ elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY;
}
- BLI_spin_lock(&rb->lock_task);
- eln = lineart_list_append_pointer_pool_sized_thread(
- &rb->triangle_buffer_pointers, &rb->render_data_pool, ort, sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&rb->lock_task);
+ BLI_spin_lock(&re_buf->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->triangle_buffer_pointers,
+ &re_buf->render_data_pool,
+ la_tri_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&re_buf->lock_task);
+
+ int usage = ob_info->usage;
- eln->element_count = bm->totface;
- eln->object_ref = orig_ob;
- eln->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
+ elem_link_node->element_count = tot_tri;
+ elem_link_node->object_ref = orig_ob;
+ elem_link_node->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
/* Note this memory is not from pool, will be deleted after culling. */
- orta = MEM_callocN(sizeof(LineartTriangleAdjacent) * bm->totface, "LineartTriangleAdjacent");
+ LineartTriangleAdjacent *tri_adj = MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri,
+ "LineartTriangleAdjacent");
/* Link is minimal so we use pool anyway. */
- BLI_spin_lock(&rb->lock_task);
+ BLI_spin_lock(&re_buf->lock_task);
lineart_list_append_pointer_pool_thread(
- &rb->triangle_adjacent_pointers, &rb->render_data_pool, orta);
- BLI_spin_unlock(&rb->lock_task);
-
- for (i = 0; i < bm->totvert; i++) {
- v = BM_vert_at_index(bm, i);
- lineart_vert_transform(v, i, orv, model_view, model_view_proj);
- orv[i].index = i;
- }
+ &re_buf->triangle_adjacent_pointers, &re_buf->render_data_pool, tri_adj);
+ BLI_spin_unlock(&re_buf->lock_task);
+
+ /* Convert all vertices to lineart verts. */
+ TaskParallelSettings vert_settings;
+ BLI_parallel_range_settings_defaults(&vert_settings);
+ /* Set the minimum amount of verts a thread has to process. */
+ vert_settings.min_iter_per_thread = 4000;
+
+ VertData vert_data;
+ vert_data.mvert = me->mvert;
+ vert_data.v_arr = la_v_arr;
+ vert_data.model_view = ob_info->model_view;
+ vert_data.model_view_proj = ob_info->model_view_proj;
+
+ BLI_task_parallel_range(
+ 0, me->totvert, &vert_data, lineart_mvert_transform_task, &vert_settings);
/* Register a global index increment. See #lineart_triangle_share_edge() and
* #lineart_main_load_geometries() for detailed. It's okay that global_vindex might eventually
* overflow, in such large scene it's virtually impossible for two vertex of the same numeric
* index to come close together. */
- obi->global_i_offset = bm->totvert;
-
- tri = ort;
- for (i = 0; i < bm->totface; i++) {
- f = BM_face_at_index(bm, i);
-
- loop = f->l_first;
- tri->v[0] = &orv[BM_elem_index_get(loop->v)];
- loop = loop->next;
- tri->v[1] = &orv[BM_elem_index_get(loop->v)];
- loop = loop->next;
- tri->v[2] = &orv[BM_elem_index_get(loop->v)];
-
- /* Material mask bits and occlusion effectiveness assignment. */
- Material *mat = BKE_object_material_get(orig_ob, f->mat_nr + 1);
- tri->material_mask_bits |= ((mat && (mat->lineart.flags & LRT_MATERIAL_MASK_ENABLED)) ?
- mat->lineart.material_mask_bits :
- 0);
- tri->mat_occlusion |= (mat ? mat->lineart.mat_occlusion : 1);
- tri->flags |= (mat && (mat->blend_flag & MA_BL_CULL_BACKFACE)) ?
- LRT_TRIANGLE_MAT_BACK_FACE_CULLING :
- 0;
-
- tri->intersection_mask = obi->override_intersection_mask;
-
- double gn[3];
- copy_v3db_v3fl(gn, f->no);
- mul_v3_mat3_m4v3_db(tri->gn, normal, gn);
- normalize_v3_db(tri->gn);
-
- if (usage == OBJECT_LRT_INTERSECTION_ONLY) {
- tri->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
- }
- else if (ELEM(usage, OBJECT_LRT_NO_INTERSECTION, OBJECT_LRT_OCCLUSION_ONLY)) {
- tri->flags |= LRT_TRIANGLE_NO_INTERSECTION;
- }
-
- /* Re-use this field to refer to adjacent info, will be cleared after culling stage. */
- tri->intersecting_verts = (void *)&orta[i];
-
- tri = (LineartTriangle *)(((uchar *)tri) + rb->triangle_size);
- }
-
- /* Use BM_ELEM_TAG in f->head.hflag to store needed faces in the first iteration. */
-
- int allocate_la_e = 0;
- for (i = 0; i < bm->totedge; i++) {
- e = BM_edge_at_index(bm, i);
-
- /* Because e->head.hflag is char, so line type flags should not exceed positive 7 bits. */
- uint16_t eflag = lineart_identify_feature_line(rb,
- e,
- ort,
- orv,
- use_crease,
- use_auto_smooth,
- can_find_freestyle_edge,
- can_find_freestyle_face,
- bm);
- if (eflag) {
- /* Only allocate for feature lines (instead of all lines) to save memory.
- * If allow duplicated edges, one edge gets added multiple times if it has multiple types.
- */
- allocate_la_e += rb->allow_duplicated_types ? lineart_edge_type_duplication_count(eflag) : 1;
+ ob_info->global_i_offset = me->totvert;
+
+ /* Convert all mesh triangles into lineart triangles.
+ * Also create an edge map to get connectivity between edges and triangles. */
+ TaskParallelSettings tri_settings;
+ BLI_parallel_range_settings_defaults(&tri_settings);
+ /* Set the minimum amount of triangles a thread has to process. */
+ tri_settings.min_iter_per_thread = 4000;
+
+ TriData tri_data;
+ tri_data.ob_info = ob_info;
+ tri_data.mlooptri = mlooptri;
+ tri_data.vert_arr = la_v_arr;
+ tri_data.tri_arr = la_tri_arr;
+ tri_data.lineart_triangle_size = re_buf->triangle_size;
+ tri_data.tri_adj = tri_adj;
+
+ unsigned int total_edges = tot_tri * 3;
+
+ BLI_task_parallel_range(0, tot_tri, &tri_data, lineart_load_tri_task, &tri_settings);
+
+ /* Check for contour lines in the mesh.
+ * IE check if the triangle edges lies in area where the triangles go from front facing to back
+ * facing.
+ */
+ EdgeFeatReduceData edge_reduce = {0};
+ TaskParallelSettings edge_feat_settings;
+ BLI_parallel_range_settings_defaults(&edge_feat_settings);
+ /* Set the minimum amount of edges a thread has to process. */
+ edge_feat_settings.min_iter_per_thread = 4000;
+ edge_feat_settings.userdata_chunk = &edge_reduce;
+ edge_feat_settings.userdata_chunk_size = sizeof(EdgeFeatReduceData);
+ edge_feat_settings.func_reduce = feat_data_sum_reduce;
+
+ EdgeFeatData edge_feat_data = {0};
+ edge_feat_data.rb = re_buf;
+ edge_feat_data.me = me;
+ edge_feat_data.mlooptri = mlooptri;
+ edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
+ edge_feat_data.tri_array = la_tri_arr;
+ edge_feat_data.v_array = la_v_arr;
+ edge_feat_data.crease_threshold = crease_angle;
+ edge_feat_data.use_auto_smooth = use_auto_smooth;
+ edge_feat_data.use_freestyle_face = can_find_freestyle_face;
+ edge_feat_data.use_freestyle_edge = can_find_freestyle_edge;
+ if (edge_feat_data.use_freestyle_face) {
+ edge_feat_data.freestyle_face_index = CustomData_get_layer_index(&me->pdata,
+ CD_FREESTYLE_FACE);
+ }
+ if (edge_feat_data.use_freestyle_edge) {
+ edge_feat_data.freestyle_edge_index = CustomData_get_layer_index(&me->edata,
+ CD_FREESTYLE_EDGE);
+ }
+
+ BLI_task_parallel_range(0,
+ total_edges,
+ &edge_feat_data,
+ lineart_identify_mlooptri_feature_edges,
+ &edge_feat_settings);
+
+ LooseEdgeData loose_data = {0};
+ if (re_buf->use_loose) {
+ /* Only identifying floating edges at this point because other edges has been taken care of
+ * inside #lineart_identify_mlooptri_feature_edges function. */
+ TaskParallelSettings edge_loose_settings;
+ BLI_parallel_range_settings_defaults(&edge_loose_settings);
+ edge_loose_settings.min_iter_per_thread = 4000;
+ edge_loose_settings.func_reduce = loose_data_sum_reduce;
+ edge_loose_settings.userdata_chunk = &loose_data;
+ edge_loose_settings.userdata_chunk_size = sizeof(LooseEdgeData);
+ loose_data.me = me;
+ BLI_task_parallel_range(
+ 0, me->totedge, &loose_data, lineart_identify_loose_edges, &edge_loose_settings);
+ }
+
+ int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count;
+
+ la_edge_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ sizeof(LineartEdge) * allocate_la_e);
+ la_seg_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ sizeof(LineartEdgeSegment) * allocate_la_e);
+ BLI_spin_lock(&re_buf->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->line_buffer_pointers,
+ &re_buf->render_data_pool,
+ la_edge_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&re_buf->lock_task);
+ elem_link_node->element_count = allocate_la_e;
+ elem_link_node->object_ref = orig_ob;
+
+ // Start of the edge/seg arr
+ LineartEdge *la_edge;
+ LineartEdgeSegment *la_seg;
+ la_edge = la_edge_arr;
+ la_seg = la_seg_arr;
+
+ for (int i = 0; i < total_edges; i++) {
+ LineartEdgeNeighbor *edge_nabr = &edge_feat_data.edge_nabr[i];
+
+ if (i < edge_nabr->e) {
+ continue;
}
- /* Here we just use bm's flag for when loading actual lines, then we don't need to call
- * lineart_identify_feature_line() again, e->head.hflag deleted after loading anyway. Always
- * set the flag, so hflag stays 0 for lines that are not feature lines. */
- e->head.hflag = eflag;
- }
-
- o_la_e = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartEdge) * allocate_la_e);
- o_la_s = lineart_mem_acquire_thread(&rb->render_data_pool,
- sizeof(LineartEdgeSegment) * allocate_la_e);
- BLI_spin_lock(&rb->lock_task);
- eln = lineart_list_append_pointer_pool_sized_thread(
- &rb->line_buffer_pointers, &rb->render_data_pool, o_la_e, sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&rb->lock_task);
- eln->element_count = allocate_la_e;
- eln->object_ref = orig_ob;
-
- la_e = o_la_e;
- la_s = o_la_s;
- for (i = 0; i < bm->totedge; i++) {
- e = BM_edge_at_index(bm, i);
/* Not a feature line, so we skip. */
- if (!e->head.hflag) {
+ if (edge_nabr->flags == 0) {
continue;
}
bool edge_added = false;
/* See eLineartEdgeFlag for details. */
- for (int flag_bit = 0; flag_bit < 6; flag_bit++) {
+ for (int flag_bit = 0; flag_bit < LRT_EDGE_FLAG_TYPE_MAX_BITS; flag_bit++) {
char use_type = 1 << flag_bit;
- if (!(use_type & e->head.hflag)) {
+ if (!(use_type & edge_nabr->flags)) {
continue;
}
- la_e->v1 = &orv[BM_elem_index_get(e->v1)];
- la_e->v2 = &orv[BM_elem_index_get(e->v2)];
- la_e->v1_obindex = la_e->v1->index;
- la_e->v2_obindex = la_e->v2->index;
- if (e->l) {
- int findex = BM_elem_index_get(e->l->f);
- la_e->t1 = lineart_triangle_from_index(rb, ort, findex);
+ la_edge->v1 = &la_v_arr[edge_nabr->v1];
+ la_edge->v2 = &la_v_arr[edge_nabr->v2];
+ la_edge->v1_obindex = la_edge->v1->index;
+ la_edge->v2_obindex = la_edge->v2->index;
+ int findex = i / 3;
+ la_edge->t1 = lineart_triangle_from_index(re_buf, la_tri_arr, findex);
+ if (!edge_added) {
+ lineart_triangle_adjacent_assign(la_edge->t1, &tri_adj[findex], la_edge);
+ }
+ if (edge_nabr->e != -1) {
+ findex = edge_nabr->e / 3;
+ la_edge->t2 = lineart_triangle_from_index(re_buf, la_tri_arr, findex);
if (!edge_added) {
- lineart_triangle_adjacent_assign(la_e->t1, &orta[findex], la_e);
- }
- if (e->l->radial_next && e->l->radial_next != e->l) {
- findex = BM_elem_index_get(e->l->radial_next->f);
- la_e->t2 = lineart_triangle_from_index(rb, ort, findex);
- if (!edge_added) {
- lineart_triangle_adjacent_assign(la_e->t2, &orta[findex], la_e);
- }
+ lineart_triangle_adjacent_assign(la_edge->t2, &tri_adj[findex], la_edge);
}
}
- la_e->flags = use_type;
- la_e->object_ref = orig_ob;
- BLI_addtail(&la_e->segments, la_s);
- if (ELEM(usage, OBJECT_LRT_INHERIT, OBJECT_LRT_INCLUDE, OBJECT_LRT_NO_INTERSECTION)) {
- lineart_add_edge_to_list_thread(obi, la_e);
+ la_edge->flags = use_type;
+ la_edge->object_ref = orig_ob;
+ BLI_addtail(&la_edge->segments, la_seg);
+ if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
+ usage == OBJECT_LRT_NO_INTERSECTION) {
+ lineart_add_edge_to_list_thread(ob_info, la_edge);
}
edge_added = true;
- la_e++;
- la_s++;
+ la_edge++;
+ la_seg++;
- if (!rb->allow_duplicated_types) {
+ if (!re_buf->allow_duplicated_types) {
break;
}
}
}
- /* always free bm as it's a copy from before threading */
- BM_mesh_free(bm);
+ if (loose_data.loose_array) {
+ for (int i = 0; i < loose_data.loose_count; i++) {
+ la_edge->v1 = &la_v_arr[loose_data.loose_array[i]->v1];
+ la_edge->v2 = &la_v_arr[loose_data.loose_array[i]->v2];
+ la_edge->v1_obindex = la_edge->v1->index;
+ la_edge->v2_obindex = la_edge->v2->index;
+ la_edge->flags = LRT_EDGE_FLAG_LOOSE;
+ la_edge->object_ref = orig_ob;
+ BLI_addtail(&la_edge->segments, la_seg);
+ if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
+ usage == OBJECT_LRT_NO_INTERSECTION) {
+ lineart_add_edge_to_list_thread(ob_info, la_edge);
+ }
+ la_edge++;
+ la_seg++;
+ }
+ MEM_freeN(loose_data.loose_array);
+ }
+
+ MEM_freeN(edge_feat_data.edge_nabr);
+
+ if (ob_info->free_use_mesh) {
+ BKE_id_free(NULL, me);
+ }
}
static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
@@ -2001,6 +2262,9 @@ static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
{
for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) {
lineart_geometry_object_load(obi, olti->rb);
+ if (G.debug_value == 4000) {
+ printf("thread id: %d processed: %d\n", olti->thread_id, obi->original_me->totpoly);
+ }
}
}
@@ -2085,6 +2349,7 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_
use_olti = &olti_list[i];
}
}
+
use_olti->total_faces += this_face_count;
obi->next = use_olti->pending;
use_olti->pending = obi;
@@ -2228,8 +2493,8 @@ static void lineart_main_load_geometries(
}
else {
/* If DEG_ITER_OBJECT_FLAG_DUPLI is set, some curve objects may also have an evaluated mesh
- * object in the list. To avoid adding duplicate geometry, ignore evaluated curve objects in
- * those cases. */
+ * object in the list. To avoid adding duplicate geometry, ignore evaluated curve objects
+ * in those cases. */
if (allow_duplicates && BKE_object_get_evaluated_mesh(ob) != NULL) {
continue;
}
@@ -2259,9 +2524,12 @@ static void lineart_main_load_geometries(
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
+ if (G.debug_value == 4000) {
+ printf("thread count: %d\n", thread_count);
+ }
for (int i = 0; i < thread_count; i++) {
olti[i].rb = rb;
- olti[i].dg = depsgraph;
+ olti[i].thread_id = i;
BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, NULL);
}
BLI_task_pool_work_and_wait(tp);
@@ -3003,7 +3271,7 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
- /* If this is not the smallest subdivision bounding area. */
+ /* If this is not the smallest subdiv bounding area. */
if (ba->child) {
lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[0]);
lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[1]);
@@ -3187,7 +3455,6 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0;
rb->fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0;
rb->allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0;
- rb->remove_doubles = (lmd->calculation_flags & LRT_REMOVE_DOUBLES) != 0;
rb->use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0;
rb->use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0;
rb->use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0;
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
index 508061d5d98..b1aa81322a8 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
@@ -121,3 +121,13 @@ void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb
/* Initial bounding area row/column count, setting 4 is the simplest way algorithm could function
* efficiently. */
#define LRT_BA_ROWS 4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 7c6390971dd..1e54d5fb7ee 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -317,6 +317,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_clamp.glsl
shaders/material/gpu_shader_material_color_ramp.glsl
shaders/material/gpu_shader_material_color_util.glsl
+ shaders/material/gpu_shader_material_combine_color.glsl
shaders/material/gpu_shader_material_combine_hsv.glsl
shaders/material/gpu_shader_material_combine_rgb.glsl
shaders/material/gpu_shader_material_combine_xyz.glsl
@@ -359,6 +360,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_refraction.glsl
shaders/material/gpu_shader_material_rgb_curves.glsl
shaders/material/gpu_shader_material_rgb_to_bw.glsl
+ shaders/material/gpu_shader_material_separate_color.glsl
shaders/material/gpu_shader_material_separate_hsv.glsl
shaders/material/gpu_shader_material_separate_rgb.glsl
shaders/material/gpu_shader_material_separate_xyz.glsl
diff --git a/source/blender/gpu/metal/mtl_texture.hh b/source/blender/gpu/metal/mtl_texture.hh
index e013bb5321a..47f03a5777b 100644
--- a/source/blender/gpu/metal/mtl_texture.hh
+++ b/source/blender/gpu/metal/mtl_texture.hh
@@ -242,7 +242,7 @@ class MTLTexture : public Texture {
id<MTLBuffer> vert_buffer_mtl_;
int vert_buffer_offset_;
- /* Core parameters and subresources. */
+ /* Core parameters and sub-resources. */
eGPUTextureUsage gpu_image_usage_flags_;
/* Whether the texture's properties or state has changed (e.g. mipmap range), and re-baking of
diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm
index df3efdd12e7..7ec3d390416 100644
--- a/source/blender/gpu/metal/mtl_texture.mm
+++ b/source/blender/gpu/metal/mtl_texture.mm
@@ -563,7 +563,7 @@ void gpu::MTLTexture::update_sub(
return;
}
- /* Check Format writeability. */
+ /* Check Format write-ability. */
if (mtl_format_get_writeable_view_format(destination_format) == MTLPixelFormatInvalid) {
MTL_LOG_ERROR(
"[Error]: Updating texture -- destination MTLPixelFormat '%d' does not support write "
@@ -1769,8 +1769,8 @@ void gpu::MTLTexture::ensure_baked()
/* CUBE TEXTURES */
case GPU_TEXTURE_CUBE:
case GPU_TEXTURE_CUBE_ARRAY: {
- /* Note: For a cubemap 'Texture::d_' refers to total number of faces, not just array slices
- */
+ /* NOTE: For a cube-map 'Texture::d_' refers to total number of faces,
+ * not just array slices. */
BLI_assert(this->w_ > 0 && this->h_ > 0);
this->texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
this->texture_descriptor_.pixelFormat = mtl_format;
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
index 369fe3ac293..ae7edeb16e2 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
@@ -28,7 +28,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_clipped_uniform_color)
.fragment_out(0, Type::VEC4, "fragColor")
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
.push_constant(Type::VEC4, "color")
- /* TODO(fclem): Put thoses two to one UBO. */
+ /* TODO(@fclem): Put those two to one UBO. */
.push_constant(Type::MAT4, "ModelMatrix")
.push_constant(Type::VEC4, "ClipPlane")
.vertex_source("gpu_shader_3D_clipped_uniform_color_vert.glsl")
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
index a5c3a990d90..fe89985ae7f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
@@ -90,6 +90,56 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
outcol = vec4(rgb, hsv.w);
}
+void rgb_to_hsl(vec4 rgb, out vec4 outcol)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ l = min(1.0, (cmax + cmin) / 2.0);
+
+ if (cmax == cmin) {
+ h = s = 0.0; /* achromatic */
+ }
+ else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5 ? cdelta / (2.0 - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb[0]) {
+ h = (rgb[1] - rgb[2]) / cdelta + (rgb[1] < rgb[2] ? 6.0 : 0.0);
+ }
+ else if (cmax == rgb[1]) {
+ h = (rgb[2] - rgb[0]) / cdelta + 2.0;
+ }
+ else {
+ h = (rgb[0] - rgb[1]) / cdelta + 4.0;
+ }
+ }
+ h /= 6.0;
+
+ outcol = vec4(h, s, l, rgb.w);
+}
+
+void hsl_to_rgb(vec4 hsl, out vec4 outcol)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl[0];
+ s = hsl[1];
+ l = hsl[2];
+
+ nr = abs(h * 6.0 - 3.0) - 1.0;
+ ng = 2.0 - abs(h * 6.0 - 2.0);
+ nb = 2.0 - abs(h * 6.0 - 4.0);
+
+ nr = clamp(nr, 0.0, 1.0);
+ nb = clamp(nb, 0.0, 1.0);
+ ng = clamp(ng, 0.0, 1.0);
+
+ chroma = (1.0 - abs(2.0 * l - 1.0)) * s;
+
+ outcol = vec4((nr - 0.5) * chroma + l, (ng - 0.5) * chroma + l, (nb - 0.5) * chroma + l, hsl.w);
+}
+
void color_alpha_clear(vec4 color, out vec4 result)
{
result = vec4(color.rgb, 1.0);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl
new file mode 100644
index 00000000000..3a250fcae8b
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl
@@ -0,0 +1,16 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
+void combine_color_rgb(float r, float g, float b, out vec4 col)
+{
+ col = vec4(r, g, b, 1.0);
+}
+
+void combine_color_hsv(float h, float s, float v, out vec4 col)
+{
+ hsv_to_rgb(vec4(h, s, v, 1.0), col);
+}
+
+void combine_color_hsl(float h, float s, float l, out vec4 col)
+{
+ hsl_to_rgb(vec4(h, s, l, 1.0), col);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl
new file mode 100644
index 00000000000..7425e53ce7b
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl
@@ -0,0 +1,28 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
+void separate_color_rgb(vec4 col, out float r, out float g, out float b)
+{
+ r = col.r;
+ g = col.g;
+ b = col.b;
+}
+
+void separate_color_hsv(vec4 col, out float r, out float g, out float b)
+{
+ vec4 hsv;
+
+ rgb_to_hsv(col, hsv);
+ r = hsv[0];
+ g = hsv[1];
+ b = hsv[2];
+}
+
+void separate_color_hsl(vec4 col, out float r, out float g, out float b)
+{
+ vec4 hsl;
+
+ rgb_to_hsl(col, hsl);
+ r = hsl[0];
+ g = hsl[1];
+ b = hsl[2];
+}
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 0390df06052..8796c99629e 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -109,6 +109,14 @@ struct ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[I
/**
*
+ * \attention Defined in readimage.c
+ */
+struct ImBuf *IMB_thumb_load_image(const char *filepath,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE]);
+
+/**
+ *
* \attention Defined in allocimbuf.c
*/
void IMB_freeImBuf(struct ImBuf *ibuf);
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 31f8b3a9505..67d1aefeacb 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -36,6 +36,17 @@ typedef struct ImFileType {
char colorspace[IM_MAX_SPACE]);
/** Load an image from a file. */
struct ImBuf *(*load_filepath)(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]);
+ /**
+ * Load/Create a thumbnail image from a filepath. `max_thumb_size` is maximum size of either
+ * dimension, so can return less on either or both. Should, if possible and performant, return
+ * dimensions of the full-size image in r_width & r_height.
+ */
+ struct ImBuf *(*load_filepath_thumbnail)(const char *filepath,
+ const int flags,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height);
/** Save to a file (or memory if #IB_mem is set in `flags` and the format supports it). */
bool (*save)(struct ImBuf *ibuf, const char *filepath, int flags);
void (*load_tile)(struct ImBuf *ibuf,
@@ -143,6 +154,12 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
+struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
+ const int flags,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height);
/** \} */
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index 548bc9e120c..74042ef75be 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -33,6 +33,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_jpeg,
.load = imb_load_jpeg,
.load_filepath = NULL,
+ .load_filepath_thumbnail = imb_thumbnail_jpeg,
.save = imb_savejpeg,
.load_tile = NULL,
.flag = 0,
@@ -45,6 +46,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_png,
.load = imb_loadpng,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savepng,
.load_tile = NULL,
.flag = 0,
@@ -57,6 +59,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_bmp,
.load = imb_bmp_decode,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savebmp,
.load_tile = NULL,
.flag = 0,
@@ -69,6 +72,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_targa,
.load = imb_loadtarga,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savetarga,
.load_tile = NULL,
.flag = 0,
@@ -81,6 +85,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_iris,
.load = imb_loadiris,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_saveiris,
.load_tile = NULL,
.flag = 0,
@@ -94,6 +99,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_dpx,
.load = imb_load_dpx,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_dpx,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -106,6 +112,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_cineon,
.load = imb_load_cineon,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_cineon,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -120,6 +127,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_tiff,
.load = imb_loadtiff,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savetiff,
.load_tile = imb_loadtiletiff,
.flag = 0,
@@ -134,6 +142,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_hdr,
.load = imb_loadhdr,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savehdr,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -148,6 +157,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_openexr,
.load = imb_load_openexr,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_openexr,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -162,6 +172,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_jp2,
.load = imb_load_jp2,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_save_jp2,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -176,6 +187,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_dds,
.load = imb_load_dds,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = NULL,
.load_tile = NULL,
.flag = 0,
@@ -190,6 +202,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_photoshop,
.load = NULL,
.load_filepath = imb_load_photoshop,
+ .load_filepath_thumbnail = NULL,
.save = NULL,
.load_tile = NULL,
.flag = IM_FTYPE_FLOAT,
@@ -204,6 +217,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.is_a = imb_is_a_webp,
.load = imb_loadwebp,
.load_filepath = NULL,
+ .load_filepath_thumbnail = NULL,
.save = imb_savewebp,
.load_tile = NULL,
.flag = 0,
@@ -211,7 +225,7 @@ const ImFileType IMB_FILE_TYPES[] = {
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
},
#endif
- {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0},
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
};
const ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[ARRAY_SIZE(IMB_FILE_TYPES) - 1];
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 6fb1fb52153..80fcceb0aa7 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -39,7 +39,11 @@ static void skip_input_data(j_decompress_ptr cinfo, long num_bytes);
static void term_source(j_decompress_ptr cinfo);
static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, size_t size);
static boolean handle_app1(j_decompress_ptr cinfo);
-static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags);
+static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
+ int flags,
+ int max_size,
+ size_t *r_width,
+ size_t *r_height);
static const uchar jpeg_default_quality = 75;
static uchar ibuf_quality;
@@ -246,7 +250,11 @@ static boolean handle_app1(j_decompress_ptr cinfo)
return true;
}
-static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags)
+static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
+ int flags,
+ int max_size,
+ size_t *r_width,
+ size_t *r_height)
{
JSAMPARRAY row_pointer;
JSAMPLE *buffer = NULL;
@@ -264,16 +272,34 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
jpeg_save_markers(cinfo, JPEG_COM, 0xffff);
if (jpeg_read_header(cinfo, false) == JPEG_HEADER_OK) {
- x = cinfo->image_width;
- y = cinfo->image_height;
depth = cinfo->num_components;
if (cinfo->jpeg_color_space == JCS_YCCK) {
cinfo->out_color_space = JCS_CMYK;
}
+ if (r_width) {
+ *r_width = cinfo->image_width;
+ }
+ if (r_height) {
+ *r_height = cinfo->image_height;
+ }
+
+ if (max_size > 0) {
+ /* libjpeg can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
+ * while libjpeg-turbo can also do 3/8, 5/8, etc. But max is 1/8. */
+ float scale = (float)max_size / MAX2(cinfo->image_width, cinfo->image_height);
+ cinfo->scale_denom = 8;
+ cinfo->scale_num = max_uu(1, min_uu(8, ceill(scale * (float)cinfo->scale_denom)));
+ cinfo->dct_method = JDCT_FASTEST;
+ cinfo->dither_mode = JDITHER_ORDERED;
+ }
+
jpeg_start_decompress(cinfo);
+ x = cinfo->output_width;
+ y = cinfo->output_height;
+
if (flags & IB_test) {
jpeg_abort_decompress(cinfo);
ibuf = IMB_allocImBuf(x, y, 8 * depth, 0);
@@ -449,11 +475,92 @@ ImBuf *imb_load_jpeg(const unsigned char *buffer,
jpeg_create_decompress(cinfo);
memory_source(cinfo, buffer, size);
- ibuf = ibJpegImageFromCinfo(cinfo, flags);
+ ibuf = ibJpegImageFromCinfo(cinfo, flags, -1, NULL, NULL);
+
+ return ibuf;
+}
+
+/* Defines for JPEG Header markers and segment size. */
+#define JPEG_MARKER_MSB (0xFF)
+#define JPEG_MARKER_SOI (0xD8)
+#define JPEG_MARKER_APP1 (0xE1)
+#define JPEG_APP1_MAX (1 << 16)
+
+struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
+ const int flags,
+ const size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE],
+ size_t *r_width,
+ size_t *r_height)
+{
+ struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
+ struct my_error_mgr jerr;
+ FILE *infile = NULL;
+
+ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
+
+ cinfo->err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = jpeg_error;
+
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(cinfo);
+ return NULL;
+ }
+
+ if ((infile = BLI_fopen(filepath, "rb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filepath);
+ return NULL;
+ }
+
+ /* If file contains an embedded thumbnail, let's return that instead. */
+
+ if ((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI) &&
+ (fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_APP1)) {
+ /* This is a JPEG in Exif format (SOI + APP1), not JFIF (SOI + APP0). */
+ unsigned int i = JPEG_APP1_MAX;
+ /* All Exif data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
+ while (!((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI)) &&
+ !feof(infile) && i--)
+ ;
+ if (i > 0 && !feof(infile)) {
+ /* We found a JPEG thumbnail inside this image. */
+ ImBuf *ibuf = NULL;
+ uchar *buffer = MEM_callocN(JPEG_APP1_MAX, "thumbbuffer");
+ /* Just put SOI directly in buffer rather than seeking back 2 bytes. */
+ buffer[0] = JPEG_MARKER_MSB;
+ buffer[1] = JPEG_MARKER_SOI;
+ if (fread(buffer + 2, JPEG_APP1_MAX - 2, 1, infile) == 1) {
+ ibuf = imb_load_jpeg(buffer, JPEG_APP1_MAX, flags, colorspace);
+ }
+ MEM_SAFE_FREE(buffer);
+ if (ibuf) {
+ fclose(infile);
+ return ibuf;
+ }
+ }
+ }
+
+ /* No embedded thumbnail found, so let's create a new one. */
+
+ fseek(infile, 0, SEEK_SET);
+ jpeg_create_decompress(cinfo);
+
+ jpeg_stdio_src(cinfo, infile);
+ ImBuf *ibuf = ibJpegImageFromCinfo(cinfo, flags, max_thumb_size, r_width, r_height);
+ fclose(infile);
return ibuf;
}
+#undef JPEG_MARKER_MSB
+#undef JPEG_MARKER_SOI
+#undef JPEG_MARKER_APP1
+#undef JPEG_APP1_MAX
+
static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
{
JSAMPLE *buffer = NULL;
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index df41c0ca757..805a7e8d687 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -22,6 +22,8 @@
#include "IMB_filetype.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_metadata.h"
+#include "IMB_thumbs.h"
#include "imbuf.h"
#include "IMB_colormanagement.h"
@@ -234,6 +236,61 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S
return ibuf;
}
+struct ImBuf *IMB_thumb_load_image(const char *filepath,
+ size_t max_thumb_size,
+ char colorspace[IM_MAX_SPACE])
+{
+ const ImFileType *type = IMB_file_type_from_ftype(IMB_ispic_type(filepath));
+ if (type == NULL) {
+ return NULL;
+ }
+
+ ImBuf *ibuf = NULL;
+ int flags = IB_rect | IB_metadata;
+ /* Size of the original image. */
+ size_t width = 0;
+ size_t height = 0;
+
+ char effective_colorspace[IM_MAX_SPACE] = "";
+ if (colorspace) {
+ BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace));
+ }
+
+ if (type->load_filepath_thumbnail) {
+ ibuf = type->load_filepath_thumbnail(
+ filepath, flags, max_thumb_size, colorspace, &width, &height);
+ }
+ else {
+ /* Skip images of other types if over 100MB. */
+ const size_t file_size = BLI_file_size(filepath);
+ if (file_size != -1 && file_size > THUMB_SIZE_MAX) {
+ return NULL;
+ }
+ ibuf = IMB_loadiffname(filepath, flags, colorspace);
+ if (ibuf) {
+ width = ibuf->x;
+ height = ibuf->y;
+ }
+ }
+
+ if (ibuf) {
+ imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
+
+ if (width > 0 && height > 0) {
+ /* Save dimensions of original image into the thumbnail metadata. */
+ char cwidth[40];
+ char cheight[40];
+ SNPRINTF(cwidth, "%zu", width);
+ SNPRINTF(cheight, "%zu", height);
+ IMB_metadata_ensure(&ibuf->metadata);
+ IMB_metadata_set_field(ibuf->metadata, "Thumb::Image::Width", cwidth);
+ IMB_metadata_set_field(ibuf->metadata, "Thumb::Image::Height", cheight);
+ }
+ }
+
+ return ibuf;
+}
+
ImBuf *IMB_testiffname(const char *filepath, int flags)
{
ImBuf *ibuf;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 37734ebacb2..51951aa9605 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -318,12 +318,8 @@ static ImBuf *thumb_create_ex(const char *file_path,
char tpath[FILE_MAX];
char tdir[FILE_MAX];
char temp[FILE_MAX];
- char mtime[40] = "0"; /* in case we can't stat the file */
- char cwidth[40] = "0"; /* in case images have no data */
- char cheight[40] = "0";
+ char mtime[40] = "0"; /* in case we can't stat the file */
short tsize = 128;
- short ex, ey;
- float scaledx, scaledy;
BLI_stat_t info;
switch (size) {
@@ -340,15 +336,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
return NULL; /* unknown size */
}
- /* exception, skip images over 100mb */
- if (source == THB_SOURCE_IMAGE) {
- const size_t file_size = BLI_file_size(file_path);
- if (file_size != -1 && file_size > THUMB_SIZE_MAX) {
- // printf("file too big: %d, skipping %s\n", (int)size, file_path);
- return NULL;
- }
- }
-
if (get_thumb_dir(tdir, size)) {
BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb);
// thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
@@ -368,7 +355,7 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (img == NULL) {
switch (source) {
case THB_SOURCE_IMAGE:
- img = IMB_loadiffname(file_path, IB_rect | IB_metadata, NULL);
+ img = IMB_thumb_load_image(file_path, tsize, NULL);
break;
case THB_SOURCE_BLEND:
img = IMB_thumb_load_blend(file_path, blen_group, blen_id);
@@ -385,8 +372,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (BLI_stat(file_path, &info) != -1) {
BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime);
}
- BLI_snprintf(cwidth, sizeof(cwidth), "%d", img->x);
- BLI_snprintf(cheight, sizeof(cheight), "%d", img->y);
}
}
else if (THB_SOURCE_MOVIE == source) {
@@ -411,28 +396,20 @@ static ImBuf *thumb_create_ex(const char *file_path,
return NULL;
}
- if (img->x > img->y) {
- scaledx = (float)tsize;
- scaledy = ((float)img->y / (float)img->x) * tsize;
- }
- else {
- scaledy = (float)tsize;
- scaledx = ((float)img->x / (float)img->y) * tsize;
- }
- /* Scaling down must never assign zero width/height, see: T89868. */
- ex = MAX2(1, (short)scaledx);
- ey = MAX2(1, (short)scaledy);
-
- /* save some time by only scaling byte buf */
- if (img->rect_float) {
- if (img->rect == NULL) {
- IMB_rect_from_float(img);
+ if (img->x > tsize || img->y > tsize) {
+ float scale = MIN2((float)tsize / (float)img->x, (float)tsize / (float)img->y);
+ /* Scaling down must never assign zero width/height, see: T89868. */
+ short ex = MAX2(1, (short)(img->x * scale));
+ short ey = MAX2(1, (short)(img->y * scale));
+ /* Save some time by only scaling byte buf */
+ if (img->rect_float) {
+ if (img->rect == NULL) {
+ IMB_rect_from_float(img);
+ }
+ imb_freerectfloatImBuf(img);
}
-
- imb_freerectfloatImBuf(img);
+ IMB_scaleImBuf(img, ex, ey);
}
-
- IMB_scaleImBuf(img, ex, ey);
}
BLI_snprintf(desc, sizeof(desc), "Thumbnail for %s", uri);
IMB_metadata_ensure(&img->metadata);
@@ -443,10 +420,6 @@ static ImBuf *thumb_create_ex(const char *file_path,
if (use_hash) {
IMB_metadata_set_field(img->metadata, "X-Blender::Hash", hash);
}
- if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
- IMB_metadata_set_field(img->metadata, "Thumb::Image::Width", cwidth);
- IMB_metadata_set_field(img->metadata, "Thumb::Image::Height", cheight);
- }
img->ftype = IMB_FTYPE_PNG;
img->planes = 32;
diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt
index 67cec000778..e0fe7ed4992 100644
--- a/source/blender/io/wavefront_obj/CMakeLists.txt
+++ b/source/blender/io/wavefront_obj/CMakeLists.txt
@@ -71,6 +71,7 @@ if(WITH_GTESTS)
tests/obj_exporter_tests.cc
tests/obj_importer_tests.cc
tests/obj_mtl_parser_tests.cc
+
tests/obj_exporter_tests.hh
)
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
index d14401224ed..be322f49840 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
@@ -321,8 +321,8 @@ static bool parse_keyword(StringRef &line, StringRef keyword)
if (!line.startswith(keyword)) {
return false;
}
- /* Treat any ASCII control character as whitespace; don't use isspace() for performance reasons.
- */
+ /* Treat any ASCII control character as white-space;
+ * don't use `isspace()` for performance reasons. */
if (line[keyword_len] > ' ') {
return false;
}
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 99737aa3b67..c1dfab8a041 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -304,7 +304,7 @@ typedef struct DriverTarget {
char *rna_path;
/**
- * Name of the posebone to use
+ * Name of the pose-bone to use
* (for vars where DTAR_FLAG_STRUCT_REF is used) - `MAX_ID_NAME - 2`.
*/
char pchan_name[64];
@@ -918,9 +918,9 @@ typedef struct KS_Path {
/** Index that path affects. */
int array_index;
- /** (eInsertKeyFlags) settings to supply insertkey() with. */
+ /** (#eInsertKeyFlags) settings to supply insert-key() with. */
short keyingflag;
- /** (eInsertKeyFlags) for each flag set, the relevant keyingflag bit overrides the default. */
+ /** (#eInsertKeyFlags) for each flag set, the relevant keying-flag bit overrides the default. */
short keyingoverride;
} KS_Path;
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 3e7a4431bf5..1d5f1351de0 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -305,6 +305,12 @@ typedef enum eGP_Sculpt_Mode_Flag {
GP_SCULPT_FLAGMODE_APPLY_THICKNESS = (1 << 2),
/* apply brush to uv data */
GP_SCULPT_FLAGMODE_APPLY_UV = (1 << 3),
+ /* Stroke Auto-Masking for sculpt. */
+ GP_SCULPT_FLAGMODE_AUTOMASK_STROKE = (1 << 4),
+ /* Layer Auto-Masking for sculpt. */
+ GP_SCULPT_FLAGMODE_AUTOMASK_LAYER = (1 << 5),
+ /* Material Auto-Masking for sculpt. */
+ GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL = (1 << 6),
} eGP_Sculpt_Mode_Flag;
typedef enum eAutomasking_flag {
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 7d230b7d7a3..24e77ecf87f 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -140,6 +140,8 @@ typedef struct BrushGpencilSettings {
typedef struct BrushCurvesSculptSettings {
/** Number of curves added by the add brush. */
int add_amount;
+ /** Number of control points in new curves added by the add brush. */
+ int points_per_curve;
/* eBrushCurvesSculptFlag. */
uint32_t flag;
/** When shrinking curves, they shouldn't become shorter than this length. */
diff --git a/source/blender/makesdna/DNA_curves_types.h b/source/blender/makesdna/DNA_curves_types.h
index bb53dbafdc8..e2ad5d38bbc 100644
--- a/source/blender/makesdna/DNA_curves_types.h
+++ b/source/blender/makesdna/DNA_curves_types.h
@@ -9,6 +9,8 @@
#include "DNA_ID.h"
#include "DNA_customdata_types.h"
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -87,6 +89,9 @@ typedef struct CurvesGeometry {
* this array is allocated with a length one larger than the number of curves. This is allowed
* to be null when there are no curves.
*
+ * Every curve offset must be at least one larger than the previous.
+ * In other words, every curve must have at least one point.
+ *
* \note This is *not* stored in #CustomData because its size is one larger than #curve_data.
*/
int *curve_offsets;
@@ -130,7 +135,13 @@ typedef struct Curves {
/* Materials. */
struct Material **mat;
short totcol;
- short _pad2[3];
+
+ /**
+ * User-defined symmetry flag (#eCurvesSymmetryType) that causes editing operations to maintain
+ * symmetrical geometry.
+ */
+ char symmetry;
+ char _pad2[5];
/**
* Used as base mesh when curves represent e.g. hair or fur. This surface is used in edit modes.
@@ -150,6 +161,14 @@ enum {
HA_DS_EXPAND = (1 << 0),
};
+/** #Curves.symmetry */
+typedef enum eCurvesSymmetryType {
+ CURVES_SYMMETRY_X = 1 << 0,
+ CURVES_SYMMETRY_Y = 1 << 1,
+ CURVES_SYMMETRY_Z = 1 << 2,
+} eCurvesSymmetryType;
+ENUM_OPERATORS(eCurvesSymmetryType, CURVES_SYMMETRY_Z)
+
/* Only one material supported currently. */
#define CURVES_MATERIAL_NR 1
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index b0e7342c9cb..535533565dd 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -102,7 +102,8 @@ typedef struct NoiseGpencilModifierData {
/** Noise Frequency scaling */
float noise_scale;
float noise_offset;
- char _pad[4];
+ short noise_mode;
+ char _pad[2];
/** How many frames before recalculate randoms. */
int step;
/** Custom index for passes. */
@@ -127,6 +128,11 @@ typedef enum eNoiseGpencil_Flag {
GP_NOISE_INVERT_MATERIAL = (1 << 11),
} eNoiseGpencil_Flag;
+typedef enum eNoiseRandomGpencil_Mode {
+ GP_NOISE_RANDOM_STEP = 0,
+ GP_NOISE_RANDOM_KEYFRAME = 1,
+} eNoiseRandomGpencil_Mode;
+
typedef struct SubdivGpencilModifierData {
GpencilModifierData modifier;
/** Material for filtering. */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 4a1b639122a..a83262d7639 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -245,7 +245,7 @@ typedef struct bGPDstroke_Runtime {
/** Vertex offset in the VBO where this stroke starts. */
int stroke_start;
- /** Triangle offset in the ibo where this fill starts. */
+ /** Triangle offset in the IBO where this fill starts. */
int fill_start;
/** Curve Handles offset in the IBO where this handle starts. */
int curve_start;
@@ -814,10 +814,10 @@ typedef enum eGPdata_Flag {
/* Vertex Paint Mode - Toggle paint mode */
GP_DATA_STROKE_VERTEXMODE = (1 << 18),
- /* Autolock not active layers */
+ /* Auto-lock not active layers. */
GP_DATA_AUTOLOCK_LAYERS = (1 << 20),
- /* Enable Bezier Editing Curve (a submode of Edit mode). */
+ /* Enable Bezier Editing Curve (a sub-mode of Edit mode). */
GP_DATA_CURVE_EDIT_MODE = (1 << 21),
/* Use adaptive curve resolution */
GP_DATA_CURVE_ADAPTIVE_RESOLUTION = (1 << 22),
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index d5f7e25bb80..4ee5f34fcde 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -125,7 +125,7 @@ typedef struct ViewLayerAOV {
int type;
} ViewLayerAOV;
-/* Lightgroup Renderpass definition. */
+/** Light-group Render-pass definition. */
typedef struct ViewLayerLightgroup {
struct ViewLayerLightgroup *next, *prev;
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index 2e446427cc3..39b75b6eda2 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -21,7 +21,7 @@ typedef enum eLineartMainFlags {
LRT_ALLOW_DUPLI_OBJECTS = (1 << 2),
LRT_ALLOW_OVERLAPPING_EDGES = (1 << 3),
LRT_ALLOW_CLIPPING_BOUNDARIES = (1 << 4),
- LRT_REMOVE_DOUBLES = (1 << 5),
+ /* LRT_REMOVE_DOUBLES = (1 << 5), Deprecated */
LRT_LOOSE_AS_CONTOUR = (1 << 6),
LRT_GPENCIL_INVERT_SOURCE_VGROUP = (1 << 7),
LRT_GPENCIL_MATCH_OUTPUT_VGROUP = (1 << 8),
@@ -47,9 +47,16 @@ typedef enum eLineartEdgeFlag {
LRT_EDGE_FLAG_MATERIAL = (1 << 3),
LRT_EDGE_FLAG_INTERSECTION = (1 << 4),
LRT_EDGE_FLAG_LOOSE = (1 << 5),
- LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 6),
- LRT_EDGE_FLAG_CLIPPED = (1 << 7),
- /** Limited to 8 bits, DON'T ADD ANYMORE until improvements on the data structure. */
+ /* LRT_EDGE_FLAG_FOR_FUTURE = (1 << 7), */
+ /* Limited to 8 bits for edge type flag, don't add anymore because BMEdge->head.eflag only has 8
+ bits. So unless we changed this into a non-single-bit flag thing, we keep it this way. */
+ /** Also used as discarded line mark. */
+ LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 8),
+ LRT_EDGE_FLAG_CLIPPED = (1 << 9),
+ /** Limited to 16 bits for the entire thing. */
+
+ /** For object loading code to use only. */
+ LRT_EDGE_FLAG_INHIBIT = (1 << 14),
} eLineartEdgeFlag;
#define LRT_EDGE_FLAG_ALL_TYPE 0x3f
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index b98c9dd2886..97e057361c1 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -280,7 +280,7 @@ typedef struct Mesh {
/** Various flags used when editing the mesh. */
char editflag;
/** Mostly more flags used when editing or displaying the mesh. */
- short flag;
+ unsigned short flag;
/**
* The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index 77730ce254c..92a65a50bd4 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -632,7 +632,8 @@
.falloff = 4.0f, \
.mesh_verts_num = 0, \
.bind_verts_num = 0, \
- .polys_num = 0, \
+ .target_verts_num = 0, \
+ .target_polys_num = 0, \
.flags = 0, \
.mat = _DNA_DEFAULT_UNIT_M4, \
.strength = 1.0f, \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 73c4eeaaab3..6e3ce7e98a8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -2222,13 +2222,19 @@ typedef struct SurfaceDeformModifierData {
struct Object *target;
/** Vertex bind data. */
SDefVert *verts;
+ void *_pad1;
float falloff;
- unsigned int mesh_verts_num, bind_verts_num, polys_num;
+ /* Number of of vertices on the deformed mesh upon the bind process. */
+ unsigned int mesh_verts_num;
+ /* Number of vertices in the `verts` array of this modifier. */
+ unsigned int bind_verts_num;
+ /* Number of vertices and polygons on the target mesh upon bind process. */
+ unsigned int target_verts_num, target_polys_num;
int flags;
float mat[4][4];
float strength;
char defgrp_name[64];
- void *_pad1;
+ int _pad2;
} SurfaceDeformModifierData;
/** Surface Deform modifier flags. */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index d18fe1b81dd..92c4d8fe938 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -855,6 +855,12 @@ typedef struct NodeVertexCol {
char name[64];
} NodeVertexCol;
+typedef struct NodeCMPCombSepColor {
+ /* CMPNodeCombSepColorMode */
+ uint8_t mode;
+ uint8_t ycc_mode;
+} NodeCMPCombSepColor;
+
/** Defocus blur node. */
typedef struct NodeDefocus {
char bktype, _pad0, preview, gamco;
@@ -1485,6 +1491,11 @@ typedef struct NodeFunctionCompare {
char _pad[1];
} NodeFunctionCompare;
+typedef struct NodeCombSepColor {
+ /* NodeCombSepColorMode */
+ int8_t mode;
+} NodeCombSepColor;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1877,6 +1888,16 @@ typedef enum CMPNodeDenoisePrefilter {
CMP_NODE_DENOISE_PREFILTER_ACCURATE = 2
} CMPNodeDenoisePrefilter;
+/* Color combine/separate modes */
+
+typedef enum CMPNodeCombSepColorMode {
+ CMP_NODE_COMBSEP_COLOR_RGB = 0,
+ CMP_NODE_COMBSEP_COLOR_HSV = 1,
+ CMP_NODE_COMBSEP_COLOR_HSL = 2,
+ CMP_NODE_COMBSEP_COLOR_YCC = 3,
+ CMP_NODE_COMBSEP_COLOR_YUV = 4,
+} CMPNodeCombSepColorMode;
+
#define CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX 64
/* Point Density shader node */
@@ -2135,6 +2156,12 @@ typedef enum GeometryNodeScaleElementsMode {
GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS = 1,
} GeometryNodeScaleElementsMode;
+typedef enum NodeCombSepColorMode {
+ NODE_COMBSEP_COLOR_RGB = 0,
+ NODE_COMBSEP_COLOR_HSV = 1,
+ NODE_COMBSEP_COLOR_HSL = 2,
+} NodeCombSepColorMode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 9ea1e3a9e8d..f257833efe8 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -535,7 +535,8 @@ enum {
/** Matches #OB_TYPE_SUPPORT_EDITMODE. */
#define OB_DATA_SUPPORT_EDITMODE(_type) \
- (ELEM(_type, ID_ME, ID_CU_LEGACY, ID_MB, ID_LT, ID_AR, ID_CV))
+ (ELEM(_type, ID_ME, ID_CU_LEGACY, ID_MB, ID_LT, ID_AR) || \
+ (U.experimental.use_new_curves_tools && (_type) == ID_CV))
/* is this ID type used as object data */
#define OB_DATA_SUPPORT_ID(_id_type) \
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index c1e96bcfaf3..ef93128e5a0 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1223,7 +1223,8 @@ typedef struct SpaceImage {
char dt_uvstretch;
char around;
- char _pad1[4];
+ char gizmo_flag;
+ char _pad1[3];
int flag;
@@ -1321,6 +1322,13 @@ typedef enum eSpaceImageOverlay_Flag {
SI_OVERLAY_SHOW_GRID_BACKGROUND = (1 << 1),
} eSpaceImageOverlay_Flag;
+/** #SpaceImage.gizmo_flag */
+enum {
+ /** All gizmos. */
+ SI_GIZMO_HIDE = (1 << 0),
+ SI_GIZMO_HIDE_NAVIGATE = (1 << 1),
+};
+
/** Keep in sync with `STEPS_LEN` in `grid_frag.glsl`. */
#define SI_GRID_STEPS_LEN 8
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 3de6453bbaa..4d6e0eba915 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -643,6 +643,8 @@ typedef struct UserDef_Experimental {
/* The following options are automatically sanitized (set to 0)
* when the release cycle is not alpha. */
char use_new_curves_type;
+ /** Only available when #use_new_curves_type is enabled. */
+ char use_new_curves_tools;
char use_new_point_cloud_type;
char use_full_frame_compositor;
char use_sculpt_tools_tilt;
@@ -650,7 +652,7 @@ typedef struct UserDef_Experimental {
char use_override_templates;
char enable_eevee_next;
char use_sculpt_texture_paint;
- char _pad0[2];
+ char _pad0[1];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 86649357433..281aeae7a60 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -106,7 +106,7 @@ DNA_STRUCT_RENAME_ELEM(SDefBind, numverts, verts_num)
DNA_STRUCT_RENAME_ELEM(SDefVert, numbinds, binds_num)
DNA_STRUCT_RENAME_ELEM(SpaceSeq, overlay_type, overlay_frame_type)
DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, num_mesh_verts, mesh_verts_num)
-DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numpoly, polys_num)
+DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numpoly, target_polys_num)
DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, bind_verts_num)
DNA_STRUCT_RENAME_ELEM(SurfaceModifierData, numverts, verts_num)
DNA_STRUCT_RENAME_ELEM(Text, name, filepath)
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index 74f8e2487a4..127c8465243 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -198,8 +198,10 @@ DEF_ENUM(rna_enum_context_mode_items)
DEF_ENUM(rna_enum_preference_section_items)
DEF_ENUM(rna_enum_attribute_type_items)
+DEF_ENUM(rna_enum_color_attribute_type_items)
DEF_ENUM(rna_enum_attribute_type_with_auto_items)
DEF_ENUM(rna_enum_attribute_domain_items)
+DEF_ENUM(rna_enum_color_attribute_domain_items)
DEF_ENUM(rna_enum_attribute_domain_without_corner_items)
DEF_ENUM(rna_enum_attribute_domain_with_auto_items)
DEF_ENUM(rna_enum_geometry_component_type_items)
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index d49bac15242..2d9517ce1ee 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -40,12 +40,21 @@ const EnumPropertyItem rna_enum_attribute_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_color_attribute_type_items[] = {
+ {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color 32-bit floating-point values"},
+ {CD_PROP_BYTE_COLOR,
+ "BYTE_COLOR",
+ 0,
+ "Byte Color",
+ "RGBA color with 8-bit positive integer values"},
+ {0, NULL, 0, NULL, NULL}};
+
const EnumPropertyItem rna_enum_attribute_type_with_auto_items[] = {
{CD_AUTO_FROM_NAME, "AUTO", 0, "Auto", ""},
{CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"},
{CD_PROP_INT32, "INT", 0, "Integer", "32-bit integer"},
{CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
- {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color 32-bit floating-point values"},
+ {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color with 32-bit floating-point values"},
{CD_PROP_BYTE_COLOR,
"BYTE_COLOR",
0,
@@ -92,6 +101,11 @@ const EnumPropertyItem rna_enum_attribute_domain_with_auto_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_color_attribute_domain_items[] = {
+ {ATTR_DOMAIN_POINT, "POINT", 0, "Vertex", ""},
+ {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
+ {0, NULL, 0, NULL, NULL}};
+
#ifdef RNA_RUNTIME
# include "BLI_math.h"
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 848779c49f7..f7edba24dea 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1844,6 +1844,26 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "use_automasking_stroke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_AUTOMASK_STROKE);
+ RNA_def_property_ui_text(prop, "Auto-Masking Strokes", "Mask strokes below brush cursor");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_layer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_AUTOMASK_LAYER);
+ RNA_def_property_ui_text(prop, "Auto-Masking Layer", "Mask strokes using active layer");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_material", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL);
+ RNA_def_property_ui_text(prop, "Auto-Masking Material", "Mask strokes using active material");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
/* Material */
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Material");
@@ -1933,6 +1953,11 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
RNA_def_property_range(prop, 1, INT32_MAX);
RNA_def_property_ui_text(prop, "Add Amount", "Number of curves added by the Add brush");
+ prop = RNA_def_property(srna, "points_per_curve", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 2, INT32_MAX);
+ RNA_def_property_ui_text(
+ prop, "Points per Curve", "Number of control points in a newly added curve");
+
prop = RNA_def_property(srna, "scale_uniform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVES_SCULPT_FLAG_SCALE_UNIFORM);
RNA_def_property_ui_text(prop,
diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c
index 7a1a368551f..2dc568d0b8a 100644
--- a/source/blender/makesrna/intern/rna_curves.c
+++ b/source/blender/makesrna/intern/rna_curves.c
@@ -274,6 +274,22 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Surface", "Mesh object that the curves can be attached to");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ /* Symmetry. */
+ prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_X);
+ RNA_def_property_ui_text(prop, "X", "Enable symmetry in the X axis");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "use_mirror_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_Y);
+ RNA_def_property_ui_text(prop, "Y", "Enable symmetry in the Y axis");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "use_mirror_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_Z);
+ RNA_def_property_ui_text(prop, "Z", "Enable symmetry in the Z axis");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
/* attributes */
rna_def_attributes_common(srna);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 1f9bb972923..08986afe15e 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -232,6 +232,11 @@ static const EnumPropertyItem gpencil_envelope_mode_items[] = {
"Add fill segments to create the envelope. Don't keep the original stroke"},
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem modifier_noise_random_mode_items[] = {
+ {GP_NOISE_RANDOM_STEP, "STEP", 0, "Steps", "Apply random every N steps"},
+ {GP_NOISE_RANDOM_KEYFRAME, "KEYFRAME", 0, "On Keyframes", "Apply random every keyframe"},
+ {0, NULL, 0, NULL, NULL},
+};
#endif
#ifdef RNA_RUNTIME
@@ -959,6 +964,12 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "random_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "noise_mode");
+ RNA_def_property_enum_items(prop, modifier_noise_random_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How the random changes are applied");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
RNA_define_lib_overridable(false);
}
@@ -3259,12 +3270,6 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 30.0f);
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "use_remove_doubles", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_REMOVE_DOUBLES);
- RNA_def_property_ui_text(
- prop, "Remove Doubles", "Remove doubles from the source geometry before generating stokes");
- RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
-
prop = RNA_def_property(srna, "use_loose_as_contour", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_LOOSE_AS_CONTOUR);
RNA_def_property_ui_text(prop, "Loose As Contour", "Loose edges will have contour type");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index eaf2142495e..4cd12acd038 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -489,6 +489,13 @@ static const EnumPropertyItem rna_node_geometry_curve_handle_side_items[] = {
{GEO_NODE_CURVE_HANDLE_RIGHT, "RIGHT", ICON_NONE, "Right", "Use the right handles"},
{0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem rna_node_combsep_color_items[] = {
+ {NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
static const EnumPropertyItem node_sampler_type_items[] = {
{0, "NEAREST", 0, "Nearest", ""},
@@ -5050,6 +5057,18 @@ static void def_fn_input_string(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_fn_combsep_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_combsep_color_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
/* -- Shader Nodes ---------------------------------------------------------- */
static void def_sh_output(StructRNA *srna)
@@ -5401,6 +5420,17 @@ static void def_sh_tex_image(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Node_update");
}
+static void def_tex_combsep_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_node_combsep_color_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_image_texture(StructRNA *srna)
{
static const EnumPropertyItem fn_tex_prop_interpolation_items[] = {
@@ -6308,6 +6338,25 @@ static void def_sh_output_aov(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "bNode", NULL);
}
+static void def_sh_combsep_color(StructRNA *srna)
+{
+ static const EnumPropertyItem type_items[] = {
+ {NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_sh_script(StructRNA *srna)
{
PropertyRNA *prop;
@@ -8071,6 +8120,32 @@ static void def_cmp_ycc(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_combsep_color(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+ {CMP_NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {CMP_NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {CMP_NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {CMP_NODE_COMBSEP_COLOR_YCC, "YCC", ICON_NONE, "YCbCr", "Use YCbCr color processing"},
+ {CMP_NODE_COMBSEP_COLOR_YUV, "YUV", ICON_NONE, "YUV", "Use YUV color processing"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCMPCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "ycc_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, node_ycc_items);
+ RNA_def_property_ui_text(prop, "Color Space", "Color space used for YCbCrA processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_movieclip(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 1a9e7f5aad8..11a1cf95d52 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -5407,6 +5407,17 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Show Mask Editor", "Show Mask editing related properties");
+ /* Gizmo Toggles. */
+ prop = RNA_def_property(srna, "show_gizmo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", SI_GIZMO_HIDE);
+ RNA_def_property_ui_text(prop, "Show Gizmo", "Show gizmos of all types");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
+ prop = RNA_def_property(srna, "show_gizmo_navigate", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", SI_GIZMO_HIDE_NAVIGATE);
+ RNA_def_property_ui_text(prop, "Navigate Gizmo", "Viewport navigation gizmo");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
/* Overlays */
prop = RNA_def_property(srna, "overlay", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 1a2017f2dbb..5ac324b3627 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -1101,6 +1101,16 @@ int rna_show_statusbar_vram_editable(struct PointerRNA *UNUSED(ptr), const char
return GPU_mem_stats_supported() ? PROP_EDITABLE : 0;
}
+static int rna_userdef_experimental_use_new_curve_tools_editable(struct PointerRNA *UNUSED(ptr),
+ const char **r_info)
+{
+ if (U.experimental.use_new_curves_type) {
+ return PROP_EDITABLE;
+ }
+ *r_info = "Only available when new curves type is enabled";
+ return 0;
+}
+
#else
# define USERDEF_TAG_DIRTY_PROPERTY_UPDATE_ENABLE \
@@ -6394,6 +6404,12 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_new_curves_type", 1);
RNA_def_property_ui_text(prop, "New Curves Type", "Enable the new curves data type in the UI");
+ prop = RNA_def_property(srna, "use_new_curves_tools", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_new_curves_tools", 1);
+ RNA_def_property_editable_func(prop, "rna_userdef_experimental_use_new_curve_tools_editable");
+ RNA_def_property_ui_text(
+ prop, "New Curves Tools", "Enable additional features for the new curves data block");
+
prop = RNA_def_property(srna, "use_cycles_debug", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_cycles_debug", 1);
RNA_def_property_ui_text(prop, "Cycles Debug", "Enable Cycles debugging options for developers");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index b09a9ab0733..0ac6dc7aaa9 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -896,8 +896,10 @@ static void rna_wmKeyMapItem_map_type_set(PointerRNA *ptr, int value)
}
}
-/* assumes value to be an enum from rna_enum_event_type_items */
-/* function makes sure keymodifiers are only valid keys, ESC keeps it unaltered */
+/**
+ * Assumes value to be an enum from rna_enum_event_type_items.
+ * Function makes sure keymodifiers are only valid keys, ESC keeps it unaltered.
+ */
static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value)
{
wmKeyMapItem *kmi = ptr->data;
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index a80918b8d2b..8a0f49efb65 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -1166,8 +1166,8 @@ static bool surfacedeformBind(Object *ob,
SurfaceDeformModifierData *smd_eval,
float (*vertexCos)[3],
uint verts_num,
- uint tpolys_num,
- uint tverts_num,
+ uint target_polys_num,
+ uint target_verts_num,
Mesh *target,
Mesh *mesh)
{
@@ -1182,7 +1182,7 @@ static bool surfacedeformBind(Object *ob,
SDefAdjacency *adj_array;
SDefEdgePolys *edge_polys;
- vert_edges = MEM_calloc_arrayN(tverts_num, sizeof(*vert_edges), "SDefVertEdgeMap");
+ vert_edges = MEM_calloc_arrayN(target_verts_num, sizeof(*vert_edges), "SDefVertEdgeMap");
if (vert_edges == NULL) {
BKE_modifier_set_error(ob, (ModifierData *)smd_eval, "Out of memory");
return false;
@@ -1220,7 +1220,7 @@ static bool surfacedeformBind(Object *ob,
}
adj_result = buildAdjacencyMap(
- mpoly, medge, mloop, tpolys_num, tedges_num, vert_edges, adj_array, edge_polys);
+ mpoly, medge, mloop, target_polys_num, tedges_num, vert_edges, adj_array, edge_polys);
if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
BKE_modifier_set_error(
@@ -1233,7 +1233,8 @@ static bool surfacedeformBind(Object *ob,
}
smd_orig->mesh_verts_num = verts_num;
- smd_orig->polys_num = tpolys_num;
+ smd_orig->target_verts_num = target_verts_num;
+ smd_orig->target_polys_num = target_polys_num;
int defgrp_index;
MDeformVert *dvert;
@@ -1249,7 +1250,8 @@ static bool surfacedeformBind(Object *ob,
.medge = medge,
.mloop = mloop,
.looptri = BKE_mesh_runtime_looptri_ensure(target),
- .targetCos = MEM_malloc_arrayN(tverts_num, sizeof(float[3]), "SDefTargetBindVertArray"),
+ .targetCos = MEM_malloc_arrayN(
+ target_verts_num, sizeof(float[3]), "SDefTargetBindVertArray"),
.bind_verts = smd_orig->verts,
.vertexCos = vertexCos,
.falloff = smd_orig->falloff,
@@ -1268,7 +1270,7 @@ static bool surfacedeformBind(Object *ob,
invert_m4_m4(data.imat, smd_orig->mat);
- for (int i = 0; i < tverts_num; i++) {
+ for (int i = 0; i < target_verts_num; i++) {
mul_v3_m4v3(data.targetCos[i], smd_orig->mat, mvert[i].co);
}
@@ -1431,7 +1433,7 @@ static void surfacedeformModifier_do(ModifierData *md,
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
Mesh *target;
- uint tverts_num, tpolys_num;
+ uint target_verts_num, target_polys_num;
/* Exit function if bind flag is not set (free bind data if any). */
if (!(smd->flags & MOD_SDEF_BIND)) {
@@ -1453,8 +1455,8 @@ static void surfacedeformModifier_do(ModifierData *md,
return;
}
- tverts_num = BKE_mesh_wrapper_vert_len(target);
- tpolys_num = BKE_mesh_wrapper_poly_len(target);
+ target_verts_num = BKE_mesh_wrapper_vert_len(target);
+ target_polys_num = BKE_mesh_wrapper_poly_len(target);
/* If not bound, execute bind. */
if (smd->verts == NULL) {
@@ -1473,25 +1475,62 @@ static void surfacedeformModifier_do(ModifierData *md,
/* Avoid converting edit-mesh data, binding is an exception. */
BKE_mesh_wrapper_ensure_mdata(target);
- if (!surfacedeformBind(
- ob, smd_orig, smd, vertexCos, verts_num, tpolys_num, tverts_num, target, mesh)) {
+ if (!surfacedeformBind(ob,
+ smd_orig,
+ smd,
+ vertexCos,
+ verts_num,
+ target_polys_num,
+ target_verts_num,
+ target,
+ mesh)) {
smd->flags &= ~MOD_SDEF_BIND;
}
/* Early abort, this is binding 'call', no need to perform whole evaluation. */
return;
}
- /* Poly count checks */
+ /* Geometry count on the deforming mesh. */
if (smd->mesh_verts_num != verts_num) {
BKE_modifier_set_error(
ob, md, "Vertices changed from %u to %u", smd->mesh_verts_num, verts_num);
return;
}
- if (smd->polys_num != tpolys_num) {
+
+ /* Geometry count on the target mesh. */
+ if (smd->target_polys_num != target_polys_num && smd->target_verts_num == 0) {
+ /* Change in the number of polygons does not really imply change in the vertex count, but
+ * this is how the modifier worked before the vertex count was known. Follow the legacy
+ * logic without requirement to re-bind the mesh. */
BKE_modifier_set_error(
- ob, md, "Target polygons changed from %u to %u", smd->polys_num, tpolys_num);
+ ob, md, "Target polygons changed from %u to %u", smd->target_polys_num, target_polys_num);
return;
}
+ if (smd->target_verts_num != 0 && smd->target_verts_num != target_verts_num) {
+ if (smd->target_verts_num > target_verts_num) {
+ /* Number of vertices on the target did reduce. There is no usable recovery from this. */
+ BKE_modifier_set_error(ob,
+ md,
+ "Target vertices changed from %u to %u",
+ smd->target_verts_num,
+ target_verts_num);
+ return;
+ }
+
+ /* Assume the increase in the vertex count means that the "new" vertices in the target mesh are
+ * added after the original ones. This covers typical case when target was at the subdivision
+ * level 0 and then subdivision was increased (i.e. for the render purposes). */
+
+ BKE_modifier_set_error(ob,
+ md,
+ "Target vertices changed from %u to %u, continuing anyway",
+ smd->target_verts_num,
+ target_verts_num);
+
+ /* In theory we only need the `smd->verts_num` vertices in the `targetCos` for evaluation, but
+ * it is not currently possible to request a subset of coordinates: the API expects that the
+ * caller needs coordinates of all vertices and asserts for it. */
+ }
/* Early out if modifier would not affect input at all - still *after* the sanity checks
* (and potential binding) above. */
@@ -1507,7 +1546,7 @@ static void surfacedeformModifier_do(ModifierData *md,
/* Actual vertex location update starts here */
SDefDeformData data = {
.bind_verts = smd->verts,
- .targetCos = MEM_malloc_arrayN(tverts_num, sizeof(float[3]), "SDefTargetVertArray"),
+ .targetCos = MEM_malloc_arrayN(target_verts_num, sizeof(float[3]), "SDefTargetVertArray"),
.vertexCos = vertexCos,
.dvert = dvert,
.defgrp_index = defgrp_index,
@@ -1516,7 +1555,8 @@ static void surfacedeformModifier_do(ModifierData *md,
};
if (data.targetCos != NULL) {
- BKE_mesh_wrapper_vert_coords_copy_with_mat4(target, data.targetCos, tverts_num, smd->mat);
+ BKE_mesh_wrapper_vert_coords_copy_with_mat4(
+ target, data.targetCos, target_verts_num, smd->mat);
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 3d3450d9252..5d782674f16 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -126,6 +126,8 @@ void register_node_type_cmp_planetrackdeform(void);
void register_node_type_cmp_cornerpin(void);
void register_node_type_cmp_separate_xyz(void);
void register_node_type_cmp_combine_xyz(void);
+void register_node_type_cmp_separate_color(void);
+void register_node_type_cmp_combine_color(void);
void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node);
void node_cmp_rlayers_register_pass(struct bNodeTree *ntree,
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index cde4b67e120..ad96fba1929 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -8,6 +8,7 @@ extern "C" {
void register_node_type_fn_align_euler_to_vector(void);
void register_node_type_fn_boolean_math(void);
+void register_node_type_fn_combine_color(void);
void register_node_type_fn_compare(void);
void register_node_type_fn_float_to_int(void);
void register_node_type_fn_input_bool(void);
@@ -19,6 +20,7 @@ void register_node_type_fn_input_vector(void);
void register_node_type_fn_random_value(void);
void register_node_type_fn_replace_string(void);
void register_node_type_fn_rotate_euler(void);
+void register_node_type_fn_separate_color(void);
void register_node_type_fn_slice_string(void);
void register_node_type_fn_string_length(void);
void register_node_type_fn_value_to_string(void);
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 4996f12e27d..1d1310360b8 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -43,6 +43,8 @@ void register_node_type_sh_vect_math(void);
void register_node_type_sh_squeeze(void);
void register_node_type_sh_dynamic(void);
void register_node_type_sh_invert(void);
+void register_node_type_sh_sepcolor(void);
+void register_node_type_sh_combcolor(void);
void register_node_type_sh_seprgb(void);
void register_node_type_sh_combrgb(void);
void register_node_type_sh_sephsv(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 5818fa631e7..7dd732e7fad 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -42,8 +42,8 @@ DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH",
DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )
DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
-DefNode(ShaderNode, SH_NODE_SEPRGB, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
-DefNode(ShaderNode, SH_NODE_COMBRGB, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
+DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
+DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "" )
@@ -106,8 +106,8 @@ DefNode(ShaderNode, SH_NODE_TEX_POINTDENSITY, def_sh_tex_pointdensity,"TEX
DefNode(ShaderNode, SH_NODE_TEX_COORD, def_sh_tex_coord, "TEX_COORD", TexCoord, "Texture Coordinate","" )
DefNode(ShaderNode, SH_NODE_VECTOR_ROTATE, def_sh_vector_rotate, "VECTOR_ROTATE", VectorRotate, "Vector Rotate", "" )
DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VECT_TRANSFORM", VectorTransform, "Vector Transform", "" )
-DefNode(ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
-DefNode(ShaderNode, SH_NODE_COMBHSV, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
+DefNode(ShaderNode, SH_NODE_SEPHSV_LEGACY, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
+DefNode(ShaderNode, SH_NODE_COMBHSV_LEGACY, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" )
DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Color Attribute", "" )
DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" )
@@ -120,6 +120,8 @@ DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX
DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "" )
DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "" )
+DefNode(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
+DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
@@ -137,8 +139,8 @@ DefNode(CompositorNode, CMP_NODE_MAP_VALUE, def_cmp_map_value, "MAP_VA
DefNode(CompositorNode, CMP_NODE_MAP_RANGE, def_cmp_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
DefNode(CompositorNode, CMP_NODE_TIME, def_time, "TIME", Time, "Time Curve", "" )
DefNode(CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBLUR", VecBlur, "Vector Blur", "" )
-DefNode(CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
-DefNode(CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPRGBA_LEGACY, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPHSVA_LEGACY, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
DefNode(CompositorNode, CMP_NODE_SETALPHA, def_cmp_set_alpha, "SETALPHA", SetAlpha, "Set Alpha", "" )
DefNode(CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue Saturation Value","" )
DefNode(CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" )
@@ -149,16 +151,16 @@ DefNode(CompositorNode, CMP_NODE_OUTPUT_FILE, 0, "OUTPUT
DefNode(CompositorNode, CMP_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" )
DefNode(CompositorNode, CMP_NODE_TRANSLATE, def_cmp_translate, "TRANSLATE", Translate, "Translate", "" )
DefNode(CompositorNode, CMP_NODE_ZCOMBINE, def_cmp_zcombine, "ZCOMBINE", Zcombine, "Z Combine", "" )
-DefNode(CompositorNode, CMP_NODE_COMBRGBA, 0, "COMBRGBA", CombRGBA, "Combine RGBA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBRGBA_LEGACY,0, "COMBRGBA", CombRGBA, "Combine RGBA", "" )
DefNode(CompositorNode, CMP_NODE_DILATEERODE, def_cmp_dilate_erode, "DILATEERODE", DilateErode, "Dilate/Erode", "" )
DefNode(CompositorNode, CMP_NODE_INPAINT, def_cmp_inpaint, "INPAINT", Inpaint, "Inpaint", "" )
DefNode(CompositorNode, CMP_NODE_DESPECKLE, def_cmp_despeckle, "DESPECKLE", Despeckle, "Despeckle", "" )
DefNode(CompositorNode, CMP_NODE_ROTATE, def_cmp_rotate, "ROTATE", Rotate, "Rotate", "" )
DefNode(CompositorNode, CMP_NODE_SCALE, def_cmp_scale, "SCALE", Scale, "Scale", "" )
-DefNode(CompositorNode, CMP_NODE_SEPYCCA, def_cmp_ycc, "SEPYCCA", SepYCCA, "Separate YCbCrA", "" )
-DefNode(CompositorNode, CMP_NODE_COMBYCCA, def_cmp_ycc, "COMBYCCA", CombYCCA, "Combine YCbCrA", "" )
-DefNode(CompositorNode, CMP_NODE_SEPYUVA, 0, "SEPYUVA", SepYUVA, "Separate YUVA", "" )
-DefNode(CompositorNode, CMP_NODE_COMBYUVA, 0, "COMBYUVA", CombYUVA, "Combine YUVA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPYCCA_LEGACY, def_cmp_ycc, "SEPYCCA", SepYCCA, "Separate YCbCrA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBYCCA_LEGACY,def_cmp_ycc, "COMBYCCA", CombYCCA, "Combine YCbCrA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPYUVA_LEGACY, 0, "SEPYUVA", SepYUVA, "Separate YUVA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBYUVA_LEGACY,0, "COMBYUVA", CombYUVA, "Combine YUVA", "" )
DefNode(CompositorNode, CMP_NODE_DIFF_MATTE, def_cmp_diff_matte, "DIFF_MATTE", DiffMatte, "Difference Key", "" )
DefNode(CompositorNode, CMP_NODE_COLOR_SPILL, def_cmp_color_spill, "COLOR_SPILL", ColorSpill, "Color Spill", "" )
DefNode(CompositorNode, CMP_NODE_CHROMA_MATTE, def_cmp_chroma_matte, "CHROMA_MATTE", ChromaMatte, "Chroma Key", "" )
@@ -170,7 +172,7 @@ DefNode(CompositorNode, CMP_NODE_ID_MASK, def_cmp_id_mask, "ID_MAS
DefNode(CompositorNode, CMP_NODE_DOUBLEEDGEMASK, def_cmp_double_edge_mask,"DOUBLEEDGEMASK", DoubleEdgeMask, "Double Edge Mask", "" )
DefNode(CompositorNode, CMP_NODE_DEFOCUS, def_cmp_defocus, "DEFOCUS", Defocus, "Defocus", "" )
DefNode(CompositorNode, CMP_NODE_DISPLACE, 0, "DISPLACE", Displace, "Displace", "" )
-DefNode(CompositorNode, CMP_NODE_COMBHSVA, 0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBHSVA_LEGACY,0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
DefNode(CompositorNode, CMP_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" )
DefNode(CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" )
@@ -215,9 +217,11 @@ DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSU
DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" )
DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" )
DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" )
-DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
+DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
DefNode(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBINE_XYZ", CombineXYZ, "Combine XYZ", "" )
DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" )
+DefNode(CompositorNode, CMP_NODE_SEPARATE_COLOR, def_cmp_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
+DefNode(CompositorNode, CMP_NODE_COMBINE_COLOR, def_cmp_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
@@ -237,11 +241,13 @@ DefNode(TextureNode, TEX_NODE_VIEWER, 0, "VIEWER
DefNode(TextureNode, TEX_NODE_TRANSLATE, 0, "TRANSLATE", Translate, "Translate", "" )
DefNode(TextureNode, TEX_NODE_COORD, 0, "COORD", Coordinates, "Coordinates", "" )
DefNode(TextureNode, TEX_NODE_DISTANCE, 0, "DISTANCE", Distance, "Distance", "" )
-DefNode(TextureNode, TEX_NODE_COMPOSE, 0, "COMPOSE", Compose, "Combine RGBA", "" )
-DefNode(TextureNode, TEX_NODE_DECOMPOSE, 0, "DECOMPOSE", Decompose, "Separate RGBA", "" )
+DefNode(TextureNode, TEX_NODE_COMPOSE_LEGACY, 0, "COMPOSE", Compose, "Combine RGBA", "" )
+DefNode(TextureNode, TEX_NODE_DECOMPOSE_LEGACY,0, "DECOMPOSE", Decompose, "Separate RGBA", "" )
DefNode(TextureNode, TEX_NODE_VALTONOR, 0, "VALTONOR", ValToNor, "Value to Normal", "" )
DefNode(TextureNode, TEX_NODE_SCALE, 0, "SCALE", Scale, "Scale", "" )
DefNode(TextureNode, TEX_NODE_AT, 0, "AT", At, "At", "" )
+DefNode(TextureNode, TEX_NODE_COMBINE_COLOR, def_tex_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
+DefNode(TextureNode, TEX_NODE_SEPARATE_COLOR, def_tex_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
/* procedural textures */
DefNode(TextureNode, TEX_NODE_PROC+TEX_VORONOI, 0, "TEX_VORONOI", TexVoronoi, "Voronoi", "" )
DefNode(TextureNode, TEX_NODE_PROC+TEX_BLEND, 0, "TEX_BLEND", TexBlend, "Blend", "" )
@@ -256,6 +262,7 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DI
DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler To Vector", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
+DefNode(FunctionNode, FN_NODE_COMBINE_COLOR, def_fn_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "")
DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "")
@@ -267,6 +274,7 @@ DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR",
DefNode(FunctionNode, FN_NODE_RANDOM_VALUE, def_fn_random_value, "RANDOM_VALUE", RandomValue, "Random Value", "")
DefNode(FunctionNode, FN_NODE_REPLACE_STRING, 0, "REPLACE_STRING", ReplaceString, "Replace String", "")
DefNode(FunctionNode, FN_NODE_ROTATE_EULER, def_fn_rotate_euler, "ROTATE_EULER", RotateEuler, "Rotate Euler", "")
+DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, def_fn_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "")
DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Slice String", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
diff --git a/source/blender/nodes/NOD_texture.h b/source/blender/nodes/NOD_texture.h
index 0f07b17f165..9a2dc705c0d 100644
--- a/source/blender/nodes/NOD_texture.h
+++ b/source/blender/nodes/NOD_texture.h
@@ -46,6 +46,8 @@ void register_node_type_tex_at(void);
void register_node_type_tex_compose(void);
void register_node_type_tex_decompose(void);
+void register_node_type_tex_combine_color(void);
+void register_node_type_tex_separate_color(void);
void register_node_type_tex_proc_voronoi(void);
void register_node_type_tex_proc_blend(void);
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
index 57f76f20ac6..c0100d77889 100644
--- a/source/blender/nodes/composite/CMakeLists.txt
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -91,6 +91,7 @@ set(SRC
nodes/node_composite_rotate.cc
nodes/node_composite_scale.cc
nodes/node_composite_scene_time.cc
+ nodes/node_composite_sepcomb_color.cc
nodes/node_composite_sepcomb_hsva.cc
nodes/node_composite_sepcomb_rgba.cc
nodes/node_composite_sepcomb_xyz.cc
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc
new file mode 100644
index 00000000000..b253656a628
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_composite_util.hh"
+
+static void node_cmp_combsep_color_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeCMPCombSepColor *data = MEM_cnew<NodeCMPCombSepColor>(__func__);
+ data->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ data->ycc_mode = BLI_YCC_ITU_BT709;
+ node->storage = data;
+}
+
+static void node_cmp_combsep_color_label(const ListBase *sockets, CMPNodeCombSepColorMode mode)
+{
+ bNodeSocket *sock1 = (bNodeSocket *)sockets->first;
+ bNodeSocket *sock2 = sock1->next;
+ bNodeSocket *sock3 = sock2->next;
+
+ node_sock_label_clear(sock1);
+ node_sock_label_clear(sock2);
+ node_sock_label_clear(sock3);
+
+ switch (mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB:
+ node_sock_label(sock1, "Red");
+ node_sock_label(sock2, "Green");
+ node_sock_label(sock3, "Blue");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_HSV:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Value");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_HSL:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Lightness");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_YCC:
+ node_sock_label(sock1, "Y");
+ node_sock_label(sock2, "Cb");
+ node_sock_label(sock3, "Cr");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_YUV:
+ node_sock_label(sock1, "Y");
+ node_sock_label(sock2, "U");
+ node_sock_label(sock3, "V");
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+/* **************** SEPARATE COLOR ******************** */
+
+namespace blender::nodes::node_composite_separate_color_cc {
+
+static void cmp_node_separate_color_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void cmp_node_separate_color_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+ node_cmp_combsep_color_label(&node->outputs, (CMPNodeCombSepColorMode)storage->mode);
+}
+
+} // namespace blender::nodes::node_composite_separate_color_cc
+
+void register_node_type_cmp_separate_color()
+{
+ namespace file_ns = blender::nodes::node_composite_separate_color_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_separate_color_declare;
+ node_type_init(&ntype, node_cmp_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCMPCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, file_ns::cmp_node_separate_color_update);
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE COLOR ******************** */
+
+namespace blender::nodes::node_composite_combine_color_cc {
+
+static void cmp_node_combine_color_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void cmp_node_combine_color_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+ node_cmp_combsep_color_label(&node->inputs, (CMPNodeCombSepColorMode)storage->mode);
+}
+
+} // namespace blender::nodes::node_composite_combine_color_cc
+
+void register_node_type_cmp_combine_color()
+{
+ namespace file_ns = blender::nodes::node_composite_combine_color_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combine_color_declare;
+ node_type_init(&ntype, node_cmp_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCMPCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, file_ns::cmp_node_combine_color_update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
index 349c27d876d..a0d2485ea5a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
@@ -28,7 +28,7 @@ void register_node_type_cmp_sephsva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA_LEGACY, "Separate HSVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sephsva_declare;
nodeRegisterType(&ntype);
}
@@ -54,7 +54,7 @@ void register_node_type_cmp_combhsva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA_LEGACY, "Combine HSVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combhsva_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
index c46603be847..ae46681b0f4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
@@ -27,7 +27,7 @@ void register_node_type_cmp_seprgba()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA_LEGACY, "Separate RGBA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_seprgba_declare;
nodeRegisterType(&ntype);
@@ -54,7 +54,7 @@ void register_node_type_cmp_combrgba()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA_LEGACY, "Combine RGBA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combrgba_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
index 9b5c153fddf..a3c40b61e64 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
@@ -33,7 +33,7 @@ void register_node_type_cmp_sepycca()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA_LEGACY, "Separate YCbCrA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sepycca_declare;
node_type_init(&ntype, file_ns::node_composit_init_mode_sepycca);
@@ -66,7 +66,7 @@ void register_node_type_cmp_combycca()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA_LEGACY, "Combine YCbCrA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combycca_declare;
node_type_init(&ntype, file_ns::node_composit_init_mode_combycca);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
index e458c9cfb7e..7fdece5904d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
@@ -28,7 +28,7 @@ void register_node_type_cmp_sepyuva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA_LEGACY, "Separate YUVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sepyuva_declare;
nodeRegisterType(&ntype);
@@ -55,7 +55,7 @@ void register_node_type_cmp_combyuva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA_LEGACY, "Combine YUVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combyuva_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt
index 6ccc4c7bf5c..d03f1cb63ff 100644
--- a/source/blender/nodes/function/CMakeLists.txt
+++ b/source/blender/nodes/function/CMakeLists.txt
@@ -20,6 +20,7 @@ set(INC
set(SRC
nodes/node_fn_align_euler_to_vector.cc
nodes/node_fn_boolean_math.cc
+ nodes/node_fn_combine_color.cc
nodes/node_fn_compare.cc
nodes/node_fn_float_to_int.cc
nodes/node_fn_input_bool.cc
@@ -31,6 +32,7 @@ set(SRC
nodes/node_fn_random_value.cc
nodes/node_fn_replace_string.cc
nodes/node_fn_rotate_euler.cc
+ nodes/node_fn_separate_color.cc
nodes/node_fn_slice_string.cc
nodes/node_fn_string_length.cc
nodes/node_fn_value_to_string.cc
diff --git a/source/blender/nodes/function/nodes/node_fn_combine_color.cc b/source/blender/nodes/function/nodes/node_fn_combine_color.cc
new file mode 100644
index 00000000000..c5fd3ce38a1
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_combine_color.cc
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void fn_node_combine_color_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+};
+
+static void fn_node_combine_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void fn_node_combine_color_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static void fn_node_combine_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &bnode)
+{
+ const NodeCombSepColor &storage = node_storage(bnode);
+
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> rgba_fn{
+ "RGB", [](float r, float g, float b, float a) { return ColorGeometry4f(r, g, b, a); }};
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> hsva_fn{
+ "HSV", [](float h, float s, float v, float a) {
+ ColorGeometry4f r_color;
+ hsv_to_rgb(h, s, v, &r_color.r, &r_color.g, &r_color.b);
+ r_color.a = a;
+ return r_color;
+ }};
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> hsla_fn{
+ "HSL", [](float h, float s, float l, float a) {
+ ColorGeometry4f color;
+ hsl_to_rgb(h, s, l, &color.r, &color.g, &color.b);
+ color.a = a;
+ return color;
+ }};
+
+ switch (storage.mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return &rgba_fn;
+ case NODE_COMBSEP_COLOR_HSV:
+ return &hsva_fn;
+ case NODE_COMBSEP_COLOR_HSL:
+ return &hsla_fn;
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static void fn_node_combine_color_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_combine_color(void)
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = blender::nodes::fn_node_combine_color_declare;
+ node_type_update(&ntype, blender::nodes::fn_node_combine_color_update);
+ node_type_init(&ntype, blender::nodes::fn_node_combine_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = blender::nodes::fn_node_combine_color_build_multi_function;
+ ntype.draw_buttons = blender::nodes::fn_node_combine_color_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_separate_color.cc b/source/blender/nodes/function/nodes/node_fn_separate_color.cc
new file mode 100644
index 00000000000..1701dfdc6fa
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_separate_color.cc
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void fn_node_separate_color_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+ b.add_output<decl::Float>(N_("Alpha"));
+};
+
+static void fn_node_separate_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void fn_node_separate_color_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static void fn_node_separate_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+class SeparateRGBAFunction : public fn::MultiFunction {
+ public:
+ SeparateRGBAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Red");
+ signature.single_output<float>("Green");
+ signature.single_output<float>("Blue");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> red = params.uninitialized_single_output<float>(1, "Red");
+ MutableSpan<float> green = params.uninitialized_single_output<float>(2, "Green");
+ MutableSpan<float> blue = params.uninitialized_single_output<float>(3, "Blue");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ red[i] = colors[i].r;
+ green[i] = colors[i].g;
+ blue[i] = colors[i].b;
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+class SeparateHSVAFunction : public fn::MultiFunction {
+ public:
+ SeparateHSVAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Hue");
+ signature.single_output<float>("Saturation");
+ signature.single_output<float>("Value");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> hue = params.uninitialized_single_output<float>(1, "Hue");
+ MutableSpan<float> saturation = params.uninitialized_single_output<float>(2, "Saturation");
+ MutableSpan<float> value = params.uninitialized_single_output<float>(3, "Value");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ rgb_to_hsv(colors[i].r, colors[i].g, colors[i].b, &hue[i], &saturation[i], &value[i]);
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+class SeparateHSLAFunction : public fn::MultiFunction {
+ public:
+ SeparateHSLAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Hue");
+ signature.single_output<float>("Saturation");
+ signature.single_output<float>("Lightness");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> hue = params.uninitialized_single_output<float>(1, "Hue");
+ MutableSpan<float> saturation = params.uninitialized_single_output<float>(2, "Saturation");
+ MutableSpan<float> lightness = params.uninitialized_single_output<float>(3, "Lightness");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ rgb_to_hsl(colors[i].r, colors[i].g, colors[i].b, &hue[i], &saturation[i], &lightness[i]);
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+static void fn_node_separate_color_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const NodeCombSepColor &storage = node_storage(builder.node());
+
+ switch (storage.mode) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ static SeparateRGBAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ static SeparateHSVAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ static SeparateHSLAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_separate_color(void)
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = blender::nodes::fn_node_separate_color_declare;
+ node_type_update(&ntype, blender::nodes::fn_node_separate_color_update);
+ node_type_init(&ntype, blender::nodes::fn_node_separate_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = blender::nodes::fn_node_separate_color_build_multi_function;
+ ntype.draw_buttons = blender::nodes::fn_node_separate_color_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 7af3159bbf8..5b7211e44b4 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -81,14 +81,4 @@ void separate_geometry(GeometrySet &geometry_set,
std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
-class SplineLengthFieldInput final : public GeometryFieldInput {
- public:
- SplineLengthFieldInput();
- GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
- IndexMask mask) const final;
- uint64_t hash() const override;
- bool is_equal_to(const fn::FieldNode &other) const override;
-};
-
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index e0348f27e51..471d6af560f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -56,43 +56,6 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
}
-/** Returns the number of evaluated points in each curve. Used to deselect curves with none. */
-class EvaluatedCountFieldInput final : public GeometryFieldInput {
- public:
- EvaluatedCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Evaluated Point Count")
- {
- category_ = Category::Generated;
- }
-
- GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
- IndexMask UNUSED(mask)) const final
- {
- if (component.type() == GEO_COMPONENT_TYPE_CURVE && domain == ATTR_DOMAIN_CURVE &&
- !component.is_empty()) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const Curves &curves_id = *curve_component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- curves.ensure_evaluated_offsets();
- return VArray<int>::ForFunc(curves.curves_num(), [&](const int64_t index) -> int {
- return curves.evaluated_points_for_curve(index).size();
- });
- }
- return {};
- }
-
- uint64_t hash() const override
- {
- /* Some random constant hash. */
- return 234905872379865;
- }
-
- bool is_equal_to(const fn::FieldNode &other) const override
- {
- return dynamic_cast<const EvaluatedCountFieldInput *>(&other) != nullptr;
- }
-};
-
/**
* Return true if the attribute should be copied/interpolated to the result curves.
* Don't output attributes that correspond to curve types that have no curves in the result.
@@ -435,8 +398,6 @@ static Curves *resample_to_uniform_count(const CurveComponent &src_component,
/**
* Evaluate each selected curve to its implicit evaluated points.
- *
- * \warning Curves with no evaluated points must not be selected.
*/
static Curves *resample_to_evaluated(const CurveComponent &src_component,
const Field<bool> &selection_field)
@@ -574,7 +535,7 @@ static Field<int> get_curve_count_field(GeoNodeExecParams params,
auto get_count_op = std::make_shared<FieldOperation>(
FieldOperation(get_count_fn,
- {Field<float>(std::make_shared<SplineLengthFieldInput>()),
+ {Field<float>(std::make_shared<bke::CurveLengthFieldInput>()),
params.extract_input<Field<float>>("Length")}));
return Field<int>(std::move(get_count_op));
@@ -584,28 +545,6 @@ static Field<int> get_curve_count_field(GeoNodeExecParams params,
return {};
}
-/**
- * Create a selection field that removes curves without any evaluated points (invalid NURBS curves)
- * from the original selection provided to the node. This is here to simplify the sampling actual
- * resampling code.
- */
-static Field<bool> get_selection_field(GeoNodeExecParams params)
-{
- static fn::CustomMF_SI_SI_SO<bool, int, bool> get_selection_fn(
- "Create Curve Selection",
- [](const bool orig_selection, const int evaluated_points_num) {
- return orig_selection && evaluated_points_num > 1;
- },
- fn::CustomMF_presets::AllSpanOrSingle());
-
- auto selection_op = std::make_shared<FieldOperation>(
- FieldOperation(get_selection_fn,
- {params.extract_input<Field<bool>>("Selection"),
- Field<int>(std::make_shared<EvaluatedCountFieldInput>())}));
-
- return Field<bool>(std::move(selection_op));
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -613,7 +552,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometryCurveResample &storage = node_storage(params.node());
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
- const Field<bool> selection = get_selection_field(params);
+ const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
switch (mode) {
case GEO_NODE_CURVE_RESAMPLE_COUNT:
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index 5d97720a4f8..a548becf24e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -144,9 +144,9 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
return {};
}
-static VArray<float> construct_curve_length_varray(const bke::CurvesGeometry &curves,
- const IndexMask UNUSED(mask),
- const AttributeDomain domain)
+static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGeometry &curves,
+ const IndexMask UNUSED(mask),
+ const AttributeDomain domain)
{
curves.ensure_evaluated_lengths();
@@ -217,9 +217,9 @@ class CurveParameterFieldInput final : public GeometryFieldInput {
}
};
-class CurveLengthFieldInput final : public GeometryFieldInput {
+class CurveLengthParameterFieldInput final : public GeometryFieldInput {
public:
- CurveLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
+ CurveLengthParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
{
category_ = Category::Generated;
}
@@ -233,7 +233,7 @@ class CurveLengthFieldInput final : public GeometryFieldInput {
if (curve_component.has_curves()) {
const Curves &curves_id = *curve_component.get_for_read();
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- return construct_curve_length_varray(curves, mask, domain);
+ return construct_curve_length_parameter_varray(curves, mask, domain);
}
}
return {};
@@ -247,7 +247,7 @@ class CurveLengthFieldInput final : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override
{
- return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr;
+ return dynamic_cast<const CurveLengthParameterFieldInput *>(&other) != nullptr;
}
};
@@ -288,7 +288,7 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput {
static void node_geo_exec(GeoNodeExecParams params)
{
Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()};
- Field<float> length_field{std::make_shared<CurveLengthFieldInput>()};
+ Field<float> length_field{std::make_shared<CurveLengthParameterFieldInput>()};
Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()};
params.set_output("Factor", std::move(parameter_field));
params.set_output("Length", std::move(length_field));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index 4118448b237..6e45411a9af 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -33,52 +33,49 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-template<class T>
-static void scale_input_assign(const Span<T> input,
+template<typename T>
+static void scale_input_assign(const Span<T> src,
const int scale,
const int offset,
- const MutableSpan<T> r_output)
+ MutableSpan<T> dst)
{
- for (const int i : IndexRange(r_output.size())) {
- r_output[i] = input[i * scale + offset];
+ for (const int i : dst.index_range()) {
+ dst[i] = src[i * scale + offset];
}
}
-template<class T>
-static void scale_output_assign(const Span<T> input,
+template<typename T>
+static void scale_output_assign(const Span<T> src,
const int scale,
const int offset,
- const MutableSpan<T> &r_output)
+ MutableSpan<T> dst)
{
- for (const int i : IndexRange(input.size())) {
- r_output[i * scale + offset] = input[i];
+ for (const int i : src.index_range()) {
+ dst[i * scale + offset] = src[i];
}
}
-template<class T>
-static void nurbs_to_bezier_assign(const Span<T> input,
- const MutableSpan<T> r_output,
- const KnotsMode knotsMode)
+template<typename T>
+static void nurbs_to_bezier_assign(const Span<T> src,
+ const MutableSpan<T> dst,
+ const KnotsMode knots_mode)
{
- const int input_size = input.size();
- const int output_size = r_output.size();
-
- switch (knotsMode) {
+ switch (knots_mode) {
case NURBS_KNOT_MODE_BEZIER:
- scale_input_assign<T>(input, 3, 1, r_output);
+ scale_input_assign<T>(src, 3, 1, dst);
break;
case NURBS_KNOT_MODE_NORMAL:
- for (const int i : IndexRange(output_size)) {
- r_output[i] = input[(i + 1) % input_size];
+ for (const int i : dst.index_range()) {
+ dst[i] = src[(i + 1) % src.size()];
}
break;
case NURBS_KNOT_MODE_ENDPOINT_BEZIER:
case NURBS_KNOT_MODE_ENDPOINT:
- for (const int i : IndexRange(1, output_size - 2)) {
- r_output[i] = input[i + 1];
+ for (const int i : dst.index_range().drop_back(1).drop_front(1)) {
+ dst[i] = src[i + 1];
}
- r_output.first() = input.first();
- r_output.last() = input.last();
+ dst.first() = src.first();
+ dst.last() = src.last();
break;
}
}
@@ -357,7 +354,7 @@ static SplinePtr convert_to_nurbs(const Spline &input)
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType &storage = node_storage(params.node());
- const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage.spline_type;
+ const GeometryNodeSplineType dst_type = (const GeometryNodeSplineType)storage.spline_type;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -386,7 +383,7 @@ static void node_geo_exec(GeoNodeExecParams params)
threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
if (selection[i]) {
- switch (output_type) {
+ switch (dst_type) {
case GEO_NODE_SPLINE_TYPE_POLY:
new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]);
break;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index 6c24f86b63b..84d773ff8eb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -4,71 +4,6 @@
#include "BKE_curves.hh"
-namespace blender::nodes {
-
-/* --------------------------------------------------------------------
- * Spline Length
- */
-
-static VArray<float> construct_spline_length_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
-{
- if (!component.has_curves()) {
- return {};
- }
- const Curves &curves_id = *component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
-
- curves.ensure_evaluated_lengths();
-
- VArray<bool> cyclic = curves.cyclic();
- VArray<float> lengths = VArray<float>::ForFunc(
- curves.curves_num(), [&curves, cyclic = std::move(cyclic)](int64_t index) {
- return curves.evaluated_length_total_for_curve(index, cyclic[index]);
- });
-
- if (domain == ATTR_DOMAIN_CURVE) {
- return lengths;
- }
-
- if (domain == ATTR_DOMAIN_POINT) {
- return component.attribute_try_adapt_domain<float>(
- std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
- }
-
- return {};
-}
-
-SplineLengthFieldInput::SplineLengthFieldInput()
- : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
-{
- category_ = Category::Generated;
-}
-
-GVArray SplineLengthFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
- IndexMask UNUSED(mask)) const
-{
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_spline_length_gvarray(curve_component, domain);
- }
- return {};
-}
-
-uint64_t SplineLengthFieldInput::hash() const
-{
- /* Some random constant hash. */
- return 3549623580;
-}
-
-bool SplineLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
-{
- return dynamic_cast<const SplineLengthFieldInput *>(&other) != nullptr;
-}
-
-} // namespace blender::nodes
-
namespace blender::nodes::node_geo_input_spline_length_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -81,8 +16,8 @@ static void node_declare(NodeDeclarationBuilder &b)
* Spline Count
*/
-static VArray<int> construct_spline_count_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
+static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -117,7 +52,7 @@ class SplineCountFieldInput final : public GeometryFieldInput {
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_spline_count_gvarray(curve_component, domain);
+ return construct_curve_point_count_gvarray(curve_component, domain);
}
return {};
}
@@ -136,7 +71,7 @@ class SplineCountFieldInput final : public GeometryFieldInput {
static void node_geo_exec(GeoNodeExecParams params)
{
- Field<float> spline_length_field{std::make_shared<SplineLengthFieldInput>()};
+ Field<float> spline_length_field{std::make_shared<bke::CurveLengthFieldInput>()};
Field<int> spline_count_field{std::make_shared<SplineCountFieldInput>()};
params.set_output("Length", std::move(spline_length_field));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index 1a0cc53cb6c..2ed6d555684 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_task.hh"
+
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
@@ -41,14 +43,15 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-template<typename T>
-static void copy_attribute_to_points(const VArray<T> &src,
- const IndexMask mask,
- MutableSpan<T> dst)
+static void materialize_compressed_to_uninitialized_threaded(const GVArray &src,
+ const IndexMask mask,
+ GMutableSpan dst)
{
- for (const int i : mask.index_range()) {
- dst[i] = src[mask[i]];
- }
+ BLI_assert(src.type() == dst.type());
+ BLI_assert(mask.size() == dst.size());
+ threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
+ src.materialize_compressed_to_uninitialized(mask.slice(range), dst.slice(range).data());
+ });
}
static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
@@ -79,16 +82,21 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
- uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
geometry_set.replace_pointcloud(pointcloud);
PointCloudComponent &point_component =
geometry_set.get_component_for_write<PointCloudComponent>();
- copy_attribute_to_points(evaluator.get_evaluated<float3>(0),
- selection,
- {(float3 *)pointcloud->co, pointcloud->totpoint});
- copy_attribute_to_points(
- evaluator.get_evaluated<float>(1), selection, {pointcloud->radius, pointcloud->totpoint});
+ OutputAttribute position = point_component.attribute_try_get_for_output_only(
+ "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ materialize_compressed_to_uninitialized_threaded(
+ evaluator.get_evaluated(0), selection, position.as_span());
+ position.save();
+
+ OutputAttribute radius = point_component.attribute_try_get_for_output_only(
+ "radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
+ materialize_compressed_to_uninitialized_threaded(
+ evaluator.get_evaluated(1), selection, radius.as_span());
+ radius.save();
Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
@@ -102,11 +110,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
OutputAttribute dst = point_component.attribute_try_get_for_output_only(
attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArray<T> src_typed = src.typed<T>();
- copy_attribute_to_points(src_typed, selection, dst.as_span().typed<T>());
- });
+ materialize_compressed_to_uninitialized_threaded(src, selection, dst.as_span());
dst.save();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 4832feac5bd..f2a859065c6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_task.hh"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -21,7 +23,13 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
- b.add_input<decl::Float>(N_("Crease"))
+ b.add_input<decl::Float>(N_("Edge Crease"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .supports_field()
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Vertex Crease"))
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
@@ -44,6 +52,45 @@ static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
+#ifdef WITH_OPENSUBDIV
+static void materialize_and_clamp_creases(const VArray<float> &crease_varray,
+ MutableSpan<float> creases)
+{
+ threading::parallel_for(creases.index_range(), 1024, [&](IndexRange range) {
+ crease_varray.materialize(range, creases);
+ for (const int i : range) {
+ creases[i] = std::clamp(creases[i], 0.0f, 1.0f);
+ }
+ });
+}
+
+static void write_vertex_creases(Mesh &mesh, const VArray<float> &crease_varray)
+{
+ float *crease;
+ if (CustomData_has_layer(&mesh.vdata, CD_CREASE)) {
+ crease = static_cast<float *>(CustomData_get_layer(&mesh.vdata, CD_CREASE));
+ }
+ else {
+ crease = static_cast<float *>(
+ CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh.totvert));
+ }
+ materialize_and_clamp_creases(crease_varray, {crease, mesh.totvert});
+}
+
+static void write_edge_creases(MeshComponent &mesh, const VArray<float> &crease_varray)
+{
+ OutputAttribute_Typed<float> attribute = mesh.attribute_try_get_for_output_only<float>(
+ "crease", ATTR_DOMAIN_EDGE);
+ materialize_and_clamp_creases(crease_varray, attribute.as_span());
+ attribute.save();
+}
+
+static bool varray_is_nonzero(const VArray<float> &varray)
+{
+ return !(varray.is_single() && varray.get_internal_single() == 0.0f);
+}
+#endif
+
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
@@ -51,7 +98,8 @@ static void node_geo_exec(GeoNodeExecParams params)
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenSubdiv"));
#else
- Field<float> crease_field = params.extract_input<Field<float>>("Crease");
+ Field<float> edge_crease_field = params.extract_input<Field<float>>("Edge Crease");
+ Field<float> vertex_crease_field = params.extract_input<Field<float>>("Vertex Crease");
const NodeGeometrySubdivisionSurface &storage = node_storage(params.node());
const int uv_smooth = storage.uv_smooth;
@@ -69,27 +117,31 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- AttributeDomain domain = ATTR_DOMAIN_EDGE;
- GeometryComponentFieldContext field_context{mesh_component, domain};
- const int domain_size = mesh_component.attribute_domain_size(domain);
-
- if (domain_size == 0) {
+ const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
+ const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ if (verts_num == 0 || edges_num == 0) {
return;
}
- FieldEvaluator evaluator(field_context, domain_size);
- evaluator.add(crease_field);
- evaluator.evaluate();
- const VArray<float> &creases = evaluator.get_evaluated<float>(0);
+ GeometryComponentFieldContext point_context{mesh_component, ATTR_DOMAIN_POINT};
+ FieldEvaluator point_evaluator(point_context, verts_num);
+ point_evaluator.add(vertex_crease_field);
+ point_evaluator.evaluate();
+ const VArray<float> vertex_creases = point_evaluator.get_evaluated<float>(0);
+
+ GeometryComponentFieldContext edge_context{mesh_component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator edge_evaluator(edge_context, edges_num);
+ edge_evaluator.add(edge_crease_field);
+ edge_evaluator.evaluate();
+ const VArray<float> edge_creases = edge_evaluator.get_evaluated<float>(0);
+
+ const bool use_creases = varray_is_nonzero(vertex_creases) || varray_is_nonzero(edge_creases);
- OutputAttribute_Typed<float> crease = mesh_component.attribute_try_get_for_output_only<float>(
- "crease", domain);
- MutableSpan<float> crease_span = crease.as_span();
- for (auto i : creases.index_range()) {
- crease_span[i] = std::clamp(creases[i], 0.0f, 1.0f);
+ if (use_creases) {
+ write_vertex_creases(*geometry_set.get_mesh_for_write(), vertex_creases);
+ write_edge_creases(geometry_set.get_component_for_write<MeshComponent>(), edge_creases);
}
- crease.save();
/* Initialize mesh settings. */
SubdivToMeshSettings mesh_settings;
@@ -100,7 +152,7 @@ static void node_geo_exec(GeoNodeExecParams params)
SubdivSettings subdiv_settings;
subdiv_settings.is_simple = false;
subdiv_settings.is_adaptive = false;
- subdiv_settings.use_creases = !(creases.is_single() && creases.get_internal_single() == 0.0f);
+ subdiv_settings.use_creases = use_creases;
subdiv_settings.level = subdiv_level;
subdiv_settings.vtx_boundary_interpolation =
@@ -108,19 +160,19 @@ static void node_geo_exec(GeoNodeExecParams params)
subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
uv_smooth);
- Mesh *mesh_in = mesh_component.get_for_write();
+ const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
/* Apply subdivision to mesh. */
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in);
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, &mesh_in);
/* In case of bad topology, skip to input mesh. */
if (subdiv == nullptr) {
return;
}
- Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in);
+ Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh_in);
- mesh_component.replace(mesh_out);
+ geometry_set.replace_mesh(mesh_out);
BKE_subdiv_free(subdiv);
});
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 5d2e1663ae3..e8be093c606 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -226,6 +226,39 @@ void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *
BLI_strncpy(label, IFACE_(name), maxlen);
}
+void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode)
+{
+ bNodeSocket *sock1 = (bNodeSocket *)sockets->first;
+ bNodeSocket *sock2 = sock1->next;
+ bNodeSocket *sock3 = sock2->next;
+
+ node_sock_label_clear(sock1);
+ node_sock_label_clear(sock2);
+ node_sock_label_clear(sock3);
+
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ node_sock_label(sock1, "Red");
+ node_sock_label(sock2, "Green");
+ node_sock_label(sock3, "Blue");
+ break;
+ case NODE_COMBSEP_COLOR_HSL:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Lightness");
+ break;
+ case NODE_COMBSEP_COLOR_HSV:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Value");
+ break;
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index de03a176c0c..0a2a7a70091 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -65,6 +65,7 @@ void node_filter_label(const struct bNodeTree *ntree,
const struct bNode *node,
char *label,
int maxlen);
+void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode);
/*** Link Handling */
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
index 9b4ea0e0db6..3e90f185168 100644
--- a/source/blender/nodes/shader/CMakeLists.txt
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -82,6 +82,7 @@ set(SRC
nodes/node_shader_rgb.cc
nodes/node_shader_rgb_to_bw.cc
nodes/node_shader_script.cc
+ nodes/node_shader_sepcomb_color.cc
nodes/node_shader_sepcomb_hsv.cc
nodes/node_shader_sepcomb_rgb.cc
nodes/node_shader_sepcomb_xyz.cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc
new file mode 100644
index 00000000000..8e378ebabce
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+static void node_combsep_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+/* **************** SEPARATE COLOR ******************** */
+
+namespace blender::nodes::node_shader_separate_color_cc {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void sh_node_sepcolor_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+}
+
+static void node_sepcolor_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return "separate_color_rgb";
+ case NODE_COMBSEP_COLOR_HSV:
+ return "separate_color_hsv";
+ case NODE_COMBSEP_COLOR_HSL:
+ return "separate_color_hsl";
+ }
+
+ return nullptr;
+}
+
+static int gpu_shader_sepcolor(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.mode);
+ if (name != nullptr) {
+ return GPU_stack_link(mat, node, name, in, out);
+ }
+
+ return 0;
+}
+
+} // namespace blender::nodes::node_shader_separate_color_cc
+
+void register_node_type_sh_sepcolor()
+{
+ namespace file_ns = blender::nodes::node_shader_separate_color_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_sepcolor_declare;
+ node_type_update(&ntype, file_ns::node_sepcolor_update);
+ node_type_init(&ntype, node_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::gpu_shader_sepcolor);
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE COLOR ******************** */
+
+namespace blender::nodes::node_shader_combine_color_cc {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void sh_node_combcolor_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static void node_combcolor_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return "combine_color_rgb";
+ case NODE_COMBSEP_COLOR_HSV:
+ return "combine_color_hsv";
+ case NODE_COMBSEP_COLOR_HSL:
+ return "combine_color_hsl";
+ }
+
+ return nullptr;
+}
+
+static int gpu_shader_combcolor(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.mode);
+ if (name != nullptr) {
+ return GPU_stack_link(mat, node, name, in, out);
+ }
+
+ return 0;
+}
+
+} // namespace blender::nodes::node_shader_combine_color_cc
+
+void register_node_type_sh_combcolor()
+{
+ namespace file_ns = blender::nodes::node_shader_combine_color_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combcolor_declare;
+ node_type_update(&ntype, file_ns::node_combcolor_update);
+ node_type_init(&ntype, node_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::gpu_shader_combcolor);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
index 129c8cf4b97..6dfabe48292 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
@@ -36,7 +36,7 @@ void register_node_type_sh_sephsv()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER);
+ sh_node_type_base(&ntype, SH_NODE_SEPHSV_LEGACY, "Separate HSV", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare_sephsv;
node_type_gpu(&ntype, file_ns::gpu_shader_sephsv);
@@ -72,7 +72,7 @@ void register_node_type_sh_combhsv()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER);
+ sh_node_type_base(&ntype, SH_NODE_COMBHSV_LEGACY, "Combine HSV", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare_combhsv;
node_type_gpu(&ntype, file_ns::gpu_shader_combhsv);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 657f591a50c..28b55047633 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -76,7 +76,7 @@ void register_node_type_sh_seprgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB_LEGACY, "Separate RGB", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_seprgb_declare;
node_type_gpu(&ntype, file_ns::gpu_shader_seprgb);
ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function;
@@ -119,7 +119,7 @@ void register_node_type_sh_combrgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB_LEGACY, "Combine RGB", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_combrgb_declare;
node_type_gpu(&ntype, file_ns::gpu_shader_combrgb);
ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function;
diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt
index 7706f118507..5bed54ebfd7 100644
--- a/source/blender/nodes/texture/CMakeLists.txt
+++ b/source/blender/nodes/texture/CMakeLists.txt
@@ -24,6 +24,7 @@ set(SRC
nodes/node_texture_at.c
nodes/node_texture_bricks.c
nodes/node_texture_checker.c
+ nodes/node_texture_combine_color.c
nodes/node_texture_common.c
nodes/node_texture_compose.c
nodes/node_texture_coord.c
@@ -39,6 +40,7 @@ set(SRC
nodes/node_texture_proc.c
nodes/node_texture_rotate.c
nodes/node_texture_scale.c
+ nodes/node_texture_separate_color.c
nodes/node_texture_texture.c
nodes/node_texture_translate.c
nodes/node_texture_valToNor.c
diff --git a/source/blender/nodes/texture/nodes/node_texture_combine_color.c b/source/blender/nodes/texture/nodes/node_texture_combine_color.c
new file mode 100644
index 00000000000..459553bc950
--- /dev/null
+++ b/source/blender/nodes/texture/nodes/node_texture_combine_color.c
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup texnodes
+ */
+
+#include "BLI_listbase.h"
+#include "NOD_texture.h"
+#include "node_texture_util.h"
+
+static bNodeSocketTemplate inputs[] = {
+ {SOCK_FLOAT, N_("Red"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Green"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Blue"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {-1, ""},
+};
+static bNodeSocketTemplate outputs[] = {
+ {SOCK_RGBA, N_("Color")},
+ {-1, ""},
+};
+
+static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[i] = tex_input_value(in[i], p, thread);
+ }
+ /* Apply color space if required. */
+ switch (node->custom1) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ hsv_to_rgb_v(out, out);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ hsl_to_rgb_v(out, out);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+static void update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)node->custom1);
+}
+
+static void exec(void *data,
+ int UNUSED(thread),
+ bNode *node,
+ bNodeExecData *execdata,
+ bNodeStack **in,
+ bNodeStack **out)
+{
+ tex_output(node, execdata, in, out[0], &colorfn, data);
+}
+
+void register_node_type_tex_combine_color(void)
+{
+ static bNodeType ntype;
+
+ tex_node_type_base(&ntype, TEX_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, inputs, outputs);
+ node_type_exec(&ntype, NULL, NULL, exec);
+ node_type_update(&ntype, update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c
index e341b65ac97..ef14062c72d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_compose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_compose.c
@@ -42,7 +42,7 @@ void register_node_type_tex_compose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR);
+ tex_node_type_base(&ntype, TEX_NODE_COMPOSE_LEGACY, "Combine RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c
index 21c3944e255..2d42fa4602e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_decompose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c
@@ -62,7 +62,7 @@ void register_node_type_tex_decompose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR);
+ tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE_LEGACY, "Separate RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_separate_color.c b/source/blender/nodes/texture/nodes/node_texture_separate_color.c
new file mode 100644
index 00000000000..a482a3f3421
--- /dev/null
+++ b/source/blender/nodes/texture/nodes/node_texture_separate_color.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup texnodes
+ */
+
+#include "BLI_listbase.h"
+#include "NOD_texture.h"
+#include "node_texture_util.h"
+#include <math.h>
+
+static bNodeSocketTemplate inputs[] = {
+ {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
+ {-1, ""},
+};
+static bNodeSocketTemplate outputs[] = {
+ {SOCK_FLOAT, N_("Red")},
+ {SOCK_FLOAT, N_("Green")},
+ {SOCK_FLOAT, N_("Blue")},
+ {SOCK_FLOAT, N_("Alpha")},
+ {-1, ""},
+};
+
+static void apply_color_space(float *out, NodeCombSepColorMode type)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ rgb_to_hsv_v(out, out);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ rgb_to_hsl_v(out, out);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+static void valuefn_r(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[0];
+}
+
+static void valuefn_g(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[1];
+}
+
+static void valuefn_b(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[2];
+}
+
+static void valuefn_a(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ *out = out[3];
+}
+
+static void update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)node->custom1);
+}
+
+static void exec(void *data,
+ int UNUSED(thread),
+ bNode *node,
+ bNodeExecData *execdata,
+ bNodeStack **in,
+ bNodeStack **out)
+{
+ tex_output(node, execdata, in, out[0], &valuefn_r, data);
+ tex_output(node, execdata, in, out[1], &valuefn_g, data);
+ tex_output(node, execdata, in, out[2], &valuefn_b, data);
+ tex_output(node, execdata, in, out[3], &valuefn_a, data);
+}
+
+void register_node_type_tex_separate_color(void)
+{
+ static bNodeType ntype;
+
+ tex_node_type_base(&ntype, TEX_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, inputs, outputs);
+ node_type_exec(&ntype, NULL, NULL, exec);
+ node_type_update(&ntype, update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/python/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt
index e726cb7883d..8ccb29beb13 100644
--- a/source/blender/python/gpu/CMakeLists.txt
+++ b/source/blender/python/gpu/CMakeLists.txt
@@ -29,8 +29,8 @@ set(SRC
gpu_py_offscreen.c
gpu_py_platform.c
gpu_py_select.c
- gpu_py_shader_create_info.cc
gpu_py_shader.c
+ gpu_py_shader_create_info.cc
gpu_py_state.c
gpu_py_texture.c
gpu_py_types.c
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index a9b8d91ca03..3ee5c85c031 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -1193,8 +1193,9 @@ typedef struct wmDropBox {
struct wmDrag *drag,
const int xy[2]);
- /** Called with the draw buffer (#GPUViewport) set up for drawing into the region's view.
- * \note Only setups the drawing buffer for drawing in view, not the GPU transform matricies.
+ /**
+ * Called with the draw buffer (#GPUViewport) set up for drawing into the region's view.
+ * \note Only setups the drawing buffer for drawing in view, not the GPU transform matrices.
* The callback has to do that itself, with for example #UI_view2d_view_ortho.
* \param xy: Cursor location in window coordinates (#wmEvent.xy compatible).
*/